什么是合并挖矿
合并挖矿是指在不牺牲整体挖矿性能的情况下同时挖矿两种或多种加密货币的行为。从本质上讲,矿工可以通过使用所谓的辅助工作证明(AuxPoW ),利用他们的计算能力在多个链上同时挖掘区块。
AuxPoW 背后的想法是,在一个区块链上完成的工作可以被用作另一条链上的有效工作。提供工作量证明的区块链称为父区块链(parent blockchain ),而接受它为有效的区块链称为辅助区块链(auxiliary blockchain )。
要执行合并挖掘,所有涉及的加密货币必须使用相同的算法。例如,比特币使用 SHA-256 ,这意味着几乎任何其他使用 SHA-256 的硬币都可以与比特币一起开采——只要技术实施得当。
值得注意的是,父区块链几乎不受影响,因为它不需要进行任何类型的技术修改。另一方面,辅助区块链需要编程以有效接收和接受母链的工作。通常,添加或删除对合并挖矿的支持需要硬分叉。
从理论上讲,通过利用比特币或其他更大链的算力,合并挖矿对于小型(low-hash )区块链来说是一种提高其安全性的有趣方法。只要有足够多的矿工同意采用合并挖矿,这可能会降低 51% 攻击的可能性。
然而,许多开发人员不同意这样的想法,并声称合并挖掘提供了一种虚假的安全感。主要是因为一个相对较大的矿池在比特币上不是特别占优势,可以很容易地在较小的链上达到 51% 的哈希能力。对此的反驳是,如果奖励或激励足够好来挖掘这条辅助链,它将吸引更多的矿工,从而减少中心化并增加安全性。
除此之外,有人说合并挖矿会降低安全性,因为从过程中消除了经济损失。例如,比特币矿工可以在较小的链上使用他们的算力,而不用冒着失去比特币区块奖励的风险。因此,矿工没有理由在较小的链上诚实行事。
合并挖矿的特性
- 矿工必须构建一个与他们参与的区块链兼容的区块。例如,如果合并挖掘与比特币和
Namecoin 区块链一起使用,则在比特币区块链上生成的块将被调整为适用于两个网络,因为 Namecoin 是辅助网络,因此接受 AuxPoW 。在这种情况下,矿工可以从两个网络获得挖矿奖励。而如果区块是在 Namecoin 网络中生成的,其难度水平远低于主区块链,则它将与比特币区块链不兼容,因为比特币不识别 AuxPoW 协议。因此,矿工只能获得 Namecoin 网络中产生的奖励。 - 当在主链的
Merkle 树中添加额外的哈希时,它不会像在辅助链中那样进行任何更改或修改。在这种情况下,矿工将创建的哈希值和主区块链的区块头添加到辅助区块链,作为工作量证明。但是, AuxPoW 协议将忽略这些任意数据,并且只会将顶级哈希添加到辅助区块链中。
如何合并挖矿
以 namecoin 和 btc 为例:
Aux proof-of-work block (auxiliary blockchain)
这用于证明辅助区块链上的工作。在 vinced 的原始实现中,它是通过在父区块链客户端( bitcoind ) 上调用 getworkauxRPC 方法生成的,然后通过将其传递给辅助链客户端( namecoind )作为getauxblock 的第二个参数来提交工作。
当在 block 网络消息中接收到 Auxproof-of-workblock 时,接收到的数据类似于标准块,但在 nonce 和 txn_count 元素之间插入了额外的数据。
Bytes | Name | Data Type | Description |
---|
4 | version | int32_t | 区块版本号(不同的版本号遵守不同的区块验证规则)。 | 32 | prev_block | char[32] | 上一个区块的 SHA256(SHA256()) hash 值,是区块链的核心含义,新的数据必须包含上一个历史数据,从使得新的数据不断挂在老数据的后面。 | 32 | merkle_root | char[32] | 当前这个区块组成的 merkle tree 的根,实际上代表了当前这个区块中的所有的交易内容的摘要信息。 | 4 | timestamp | uint32_t | 区块产生的时间戳,收到这个区块的节点若是发现这个时间戳要是偏离太多会拒绝这个块。 | 4 | bits | uint32_t | 衡量矿工计算出一个块耗费代价的“当前计算难度” | 4 | nonce | uint32_t | 用于工作量证明算法的计数器 | — | — | — | — | ? | coinbase_txn | txn | 位于父区块中的 Coinbase 交易,将 AuxPOW 区块链接到其父区块 block | 32 | block_hash | char[32] | parent_block 头的哈希值 | ? | coinbase_branch | Merkle branch | 将 coinbase_txn 链接到父区块的 merkle_root 的 Merkle 分支 | ? | blockchain_branch | Merkle branch | 当在具有多个辅助链的合并挖矿设置中使用时,将这个辅助区块链链接到其他区块链的默克尔分支 | 80 | parent_block | Block header | 父区块头 | — | — | — | — | ? | txn_count | var_int | | ? | txns | tx[] | |
对于 coinbase_branchmerkle 分支,因为 coinbase 交易是区块中的第一笔交易(如果使用比特币作为父链,即下面给出的示例中的哈希 #7 ), branch_side_mask 将始终为全零,因为分支散列将始终位于工作散列的“右侧”。
当只在一个辅助区块链上工作时, blockchain_branch 链接是不需要的,并通过显示为 5 个字节的零(解释为一字节 var_int 表示分支长度为零,以及一个 32 位(4 字节)) 全零的 branch_side_mask )。
请注意,不需要 block_hash 元素,因为您拥有完整的 parent_block 标头元素,并且可以从中计算哈希值。当前的 Namecoin 客户端不检查此字段的有效性,因此一些 AuxPOW 块具有小端序,有些具有大端序。
Merkle Branch
假设 Alice 创建了一个 Merkle 树,它的根元素是公开的。例如:
merkleRoot (0)
/ \
/ \
1 2
/ \ / \
/ \ / \
3 4 5 6
/ \ / \ / \ / \
7 8 9 10 11 12 13 14
现在她想向 Bob 证明给定的哈希(#10 )是那棵树的一部分,但是 Bob 没有完整的树(只有公共根;哈希#0 )。 Alice 可以向 Bob 发送她最初用来制作树的所有哈希值(哈希值 #7-#14 ,总共 7 个额外的哈希值),因此 Bob 可以构建整个树以验证根是否相同,但这更像是数据密集型。相反,她可以给 Bob 散列#9 、#3 和#2 (来自树的每个级别一个,将#10 返回到根)。在 Bob 不知道树的结构的情况下, Alice 还必须告诉 Bob 应用散列的顺序(因为 hash(#9,#10)==#4 , 但是hash(#10 ,#9)!=#4) 。所以爱丽丝告诉鲍勃 “左,左,右” 分别指示哪个操作数 #9 、#3 和#2 。可以将其编码为位掩码并占用很少的数据进行传输。因此, Alice 不是向 Bob 传输 7 个散列,而是传输 3 个散列和一个位掩码。如果默克尔树变得更大,则节省的数据会更加明显。
这是总体前提,特别是对于 AuxPOW 协议,它被称为“默克尔分支”(因为它是默克尔树的一个路径),并通过以下方式传输:
Field Size | Description | Data type | Comments |
---|
? | branch_length | var_int | 组成分支的哈希数 | ? | branch_hash[] | char[32] | 分支中的单个 hash;重复 branch_length 次数 | 4 | branch_side_mask | int32_t | branch_hash 元素应该在默克尔散列函数的哪一侧的位掩码。零表示在右边,一表示在左边。它等于该默克尔分支的默克尔树最宽级别中起始哈希的索引。 |
首先使用第一个 branch_hash , branch_side_mask 的最低位决定了它的 hash 位置。然后第二个 branch_hash 与 branch_side_mask 的第二个最低有效位一起应用,等等。所以对于 Alice 的例子, branch_length 将是 3 ,散列将按照#9 、#3 、然后#2 的顺序给出,并且 branch_side_mask 将是 0b011=3 (等于默克尔树最宽级别中#10 的索引)。
Merged mining coinbase (parent blockchain)
父链端的工作量较小,只需在 coinbase 的 scriptSig 中插入如下格式的数据(44 字节)
Field Size | Description | Data type | Comments |
---|
4 | magic | char[4] | 0xfa, 0xbe, ‘m’, ‘m’ (仅在脚本开头超过 20 个字节时才需要;其他可选) | 32 | block_hash | char[32] | AuxPOW 区块头的哈希(默克尔分支的根) | 4 | merkle_size | int32_t | 辅助工作默克尔树中的条目数。 (必须是 2 的幂) | 4 | merkle_nonce | int32_t | Nonce 用于计算辅助工作 merkle 树的索引;只有一个辅链时设置为 0 |
作为 coinbase 脚本一部分的 44 字节字符串意味着矿工在创建 coinbase 之前构建了 AuxPOW 块。
Aux work merkle tree
如果您只是在挖掘单个辅助链并使用 getauxblock ,则不必担心这一点-只需将 coinbase 中的 merkle 树哈希设置为 getauxblock 给出的辅助链块的哈希, merkle 大小为 1 ,并将默克尔随机数设置为 0 。如果您正在挖掘多个,这有点坏了。它使用以下算法将链 ID 转换为 Merkle 树基部的槽,该链的区块哈希必须位于该槽中:
unsigned int rand = merkle_nonce;
rand = rand * 1103515245 + 12345;
rand += chain_id;
rand = rand * 1103515245 + 12345;
slot_num = rand % merkle_size
这个想法是你可以增加 merkle_nonce 直到你正在挖掘的链不会在同一个插槽上发生冲突。问题是这行不通;因为它只是将一个从 merkle_nonce 派生的数字添加到 chain_id ,如果两个链因一个随机数发生冲突,它们仍然会为所有可能的随机数发生冲突。新实现者:请选择您的 chain_id ,以便不与现有链发生冲突需要尽可能小的 merkle_size 值,或者使用更好的算法来计算您链的插槽 id 。
一旦你知道不同链在默克尔树中的位置,反转 getauxblock 给你的每个链的块哈希的字节(因此开头的字节移动到结尾等)并插入适当的插槽,填充未使用的具有任意数据的。现在像往常一样构建默克尔树,方法是获取初始行中的每一对值,然后对它们进行双 SHA-256 散列以给出新的散列行,重复此操作直到只有一个散列。最后一个哈希是默克尔根。在将其插入 coinbase 之前,您需要再次反转它的字节。如果您不使用 getauxblock 来获取块哈希,则可以跳过第一次反转,但在将其添加到 coinbase 时仍需要反转最终的默克尔根。
辅助工作量证明还需要一个默克尔分支,其构建方式如下:在默克尔树中找到区块哈希的位置,并添加您在构建默克尔树时对其进行哈希处理的另一个值。现在添加您对该结果进行哈希处理的值。继续这样做,直到你到达根部。 Merkle 根本身从不包含在 Merkle 分支中。如果您只有一个辅助链,则可以将其完全留空。(看来您也不需要反转这些哈希值。)
Example
这是 Namecoin 链中高度为 19200 的 AuxPOW 块(第一个允许 AuxPOW 身份验证的块)。它的哈希值为 d8a7c3e01e1e95bcee015e6fcc7583a2ca60b79e5a3aa0a171eddd344ada903d ,并且只有一个 Namecoin 交易(coinbase 向矿工地址发送 50NMC )。用作工作量证明的父区块的哈希值低于当时 Namecoin 的难度目标,但不是比特币目标:
0000000000003d47277359fb969c43e3c7e7c0306a17f6444b8e91e19def03a9 -- parent block hash
000000000000b269000000000000000000000000000000000000000000000000 -- Namecoin difficulty target
00000000000009ee5d0000000000000000000000000000000000000000000000 -- Bitcoin difficulty target
因此,这个 AuxPOW 区块在 Namecoin 区块链中是有效的,但在比特币区块链中无效(你会发现没有比特币区块的哈希以 3d47277359fb969c 开头。如果是,它会在 4a59b7deb5c4e01b 之后,因为这是使用的 previous_block 哈希)
Block Header:
01 01 01 00 // Version
36 90 9a c0 7a 16 73 da f6 5f a7 d8 28 88 2e 66 c9 e8 9f 85 46 cd d5 0a 9f b1 00 00 00 00 00 00 // Previous block hash
0f 5c 65 49 bc d6 08 ab 7c 4e ac 59 3e 5b d5 a7 3b 2d 43 2e b6 35 18 70 8f 77 8f c7 dc df af 88 // Merkle root
8d 1a 90 4e // Timestamp
69 b2 00 1b // Bits
00 00 00 00 // Nonce
Parent Block Coinbase Transaction:
01 00 00 00 // Version
01 // TxIn Count
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // Previous Out
00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff
35 // Script size
04 5d ee 09 1a 01 4d 52 2c fa be 6d 6d d8 a7 c3 e0 1e 1e 95 bc ee 01 5e 6f cc 75 83 a2 ca 60 b7 // Script
9e 5a 3a a0 a1 71 ed dd 34 4a da 90 3d 01 00 00 00 00 00 00 00
ff ff ff ff // Sequence Number
01 // TxOut Count
60 a0 10 2a 01 00 00 00 // Amount
43 // Script Size
41 04 f8 bb e9 7e d2 ac bc 5b ba 11 c6 8f 6f 1a 03 13 f9 18 f3 d3 c0 e8 47 50 55 e3 51 e3 bf 44 // Script
2f 8c 8d ce e6 82 d2 45 7b dc 53 51 b7 0d d9 e3 40 26 76 6e ba 18 b0 6e ae e2 e1 02 ef d1 ab 63
46 67 ac
00 00 00 00 // Lock Time
Coinbase Link:
a9 03 ef 9d e1 91 8e 4b 44 f6 17 6a 30 c0 e7 c7 e3 43 9c 96 fb 59 73 27 47 3d 00 00 00 00 00 00 // Hash of parent block header
05 // Number of links in branch
05 0a c4 a1 a1 e1 bc e0 c4 8e 55 5b 1a 9f 93 52 81 96 8c 72 d6 37 9b 24 72 9c a0 42 5a 3f c3 cb // Hash #1
43 3c d3 48 b3 5e a2 28 06 cf 21 c7 b1 46 48 9a ef 69 89 55 1e b5 ad 23 73 ab 61 21 06 0f 30 34 // Hash #2
1d 64 87 57 c0 21 7d 43 e6 6c 57 ea ed 64 fc 18 20 ec 65 d1 57 f3 3b 74 19 65 18 3a 5e 0c 85 06 // Hash #3
ac 26 02 df e2 f5 47 01 2d 1c c7 50 04 d4 8f 97 ab a4 6b d9 93 0f f2 85 c9 f2 76 f5 bd 09 f3 56 // Hash #4
df 19 72 45 79 d6 5e c7 cb 62 bf 97 94 6d fc 6f b0 e3 b2 83 9b 7f da b3 7c db 60 e5 51 22 d3 5b // Hash #5
00 00 00 00 // Branch sides bitmask
Aux Blockchain Link:
00 // Number of links in branch
00 00 00 00 // Branch sides bitmask
Parent Block Header:
01 00 00 00 // Version
08 be 13 29 5c 03 e6 7c b7 0d 00 da e8 1e a0 6e 78 b9 01 4e 5c eb 7d 9b a5 04 00 00 00 00 00 00 // Previous block hash
e0 fd 42 db 8e f6 d7 83 f0 79 d1 26 be a1 2e 2d 10 c1 04 c0 92 7c d6 8f 95 4d 85 6f 9e 81 11 e5 // Merkle root
9a 23 90 4e // Timestamp
5d ee 09 1a // Bits
1c 65 50 86 // Nonce
Transactions:
01 // Tx Count
01 00 00 00 // Version
01 // TxIn Count
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // Previous Out
00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff
08 // Script size
04 69 b2 00 1b 01 01 52 // Script
ff ff ff ff // Sequence number
01 // TxOut Count
00 f2 05 2a 01 00 00 00 // Amount
43 // Script size
41 04 89 fe 91 e6 28 47 57 5c 98 de ea b0 20 f6 5f df f1 7a 3a 87 0e bb 05 82 0b 41 4f 3d 80 97 // Script
21 8e c9 a6 5f 1e 0a e0 ac 35 af 72 47 bd 79 ed 1f 2a 24 67 5f ff b5 aa 6f 96 20 e1 92 0a d4 bf
5a a6 ac
00 00 00 00 // Lock Time
合并挖矿类型
合并挖矿按照其实现方式,主要分为两类。第一类,将辅助链的 block_hash 等数据嵌入到父链的 coinbase 中,如前面示例中的 Namecoin ,其他还有诸如 Dogecoin , Elastos 等;第二类,将 block_hash 作为一个打款地址,在 coinbasetransation 里出现:主币在创造 coinbasetransation 的时候将一笔价格为 0 的款项记打入 blockHashForMergedMining 给出的地址(hash ),代表币种有 RSK 和 Vcash 等。
以 Bitcoin 区块高度 696331 为例,对应的 RSK 区块高度为 3610440。
OP_RETURN(0x6a) + Length(0x29) + RSKBLOCK(0x52534b424c4f434b3a) + RSK Header Hash
示例中的 RSK 的 HashForMergedMining 为 0x6c54352250aee9549d5ef7381642cc612f58be59a2bc0f90509eb62a00371748 ,和 Bitcoin 对应 output 一致。
参考
|