写点什么

UTXO 与账户余额模型

  • 2019-12-05
  • 本文字数:8310 字

    阅读完需:约 27 分钟

UTXO 与账户余额模型


从写上一篇介绍区块链共识算法的文章 分布式一致性与共识算法 到现在已经过去了三个多月的时间;虽然整个行业内有非常多的变化,但是区块链技术,尤其是底层技术却没有太多的改变。这篇文章将要介绍的就是 Bitcoin 以及众多的加密货币,比如 Ethereum、NEO 和 Qtum 的底层结构究竟是什么样的。


目前的绝大多数区块链项目不是使用 _UTXO 模型_作为底层的数据结构,就是使用_账户余额模型_存储交易相关的信息。



在这篇文章中,我们会分别展示两种不同区块链模型的实现方式以及优缺点,我们会以 Bitcoin 和 Ethereum 为例分别介绍 UTXO 模型和账户余额模型。

区块与区块链

在具体介绍 UTXO 模型和账户余额模型之前,我们不得不首先介绍它们两者、甚至所有区块链应用中最重要的概念和数据结构,也就是_区块(Block)_。区块链其实就是由一个长度不断增长的链表组成的,其中包含了很多记录,也就是区块。



在上述区块链网络中,绿色的区块都被包含在主链中,所有黄色的区块都是孤块(Orphan Block),它们没有被主链接受,在每一个区块链网络中只能有一条主链,也就是最长的有效链,也是当前区块链网络中所有节点达成的共识。

区块

想要了解区块到底是什么,最简单快捷的办法就是分析它的数据结构,以 Bitcoin 中的区块 #514095 为例:


JavaScript


{  "hash":"00000000000000000018b0a6ae560fa33c469b6528bc9e0fb0c669319a186c33",  "confirmations":1009,  "strippedsize":956228,  "size":1112639,  "weight":3981323,  "height":514095,  "version":536870912,  "versionHex":"20000000",  "merkleroot":"5f8f8e053fd4c0c3175c10ac5189c15e6ba218909319850936fe54934dcbfeac",  "tx":[    // ...  ],  "time":1521380124,  "mediantime":1521377506,  "nonce":3001236454,  "bits":"17514a49",  "difficulty":3462542391191.563,  "chainwork":"0000000000000000000000000000000000000000014d2b41a340e60b72292430",  "previousblockhash":"000000000000000000481ab128418847dc25db4dafec464baa5a33e66490990b",  "nextblockhash":"0000000000000000000c74966205813839ad1c6d55d75f95c9c5f821db9c3510"}
复制代码


在这个 Block 的结构体中,previousblockhashmerkleroot 是两个最重要的字段;前者是一个哈希指针,它其实是前一个 Block 的哈希,通过 previousblockhash 我们能递归地找到全部的 Block,也就是整条主链,后者是一个 Merkle 树的根,Merkle 树中包含整个 Block 中的全部交易,通过保存 merkleroot,我们可以保证当前 Block 中任意交易都不会被修改。


Ethereum 的区块链模型虽然与 Bitcoin 有非常大的不同,但是它的 Block 结构中也有着类似的信息:


JavaScript


{   "jsonrpc":"2.0",   "result":{      "author":"0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d",      "difficulty":"0x785042b0",      "extraData":"0x414952412f7630",      "gasLimit":"0x47b784",      "gasUsed":"0x44218a",      "hash":"0x4de91e4af8d135e061d50ddd6d0d6f4119cd0f7062ebe8ff2d79c5af0e8344b9",      "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",      "miner":"0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d",      "mixHash":"0xb8155224974967443d8b83e484402fb6e1e18ff69a8fc5acdda32f2bcc6dd443",      "nonce":"0xad14fb6803147c7c",      "number":"0x2000f1",      "parentHash":"0x31919e2bf29306778f50bbc376bd490a7d056ddfd5b1f615752e79f32c7f1a38",      "receiptsRoot":"0xa2a7af5e3b9e1bbb6252ba82a09302321b8f0eea7ec8e3bb977401e4f473e672",      "sealFields":[         "0xa0b8155224974967443d8b83e484402fb6e1e18ff69a8fc5acdda32f2bcc6dd443",         "0x88ad14fb6803147c7c"      ],      "sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",      "size":"0x276",      "stateRoot":"0x87e7e54cf229003014f453d64f0344e2ba4fc7ee3b95c7dd2642cca389fa1efe",      "timestamp":"0x5a10968a",      "totalDifficulty":"0x1804de0c47ffe1",      "transactions":[...],      "transactionsRoot":"0xc2091b032961ca23cf8323ea827e8956fe6dda9e68d75bcfaa8b910035397e35",      "uncles":[]   },   "id":1}
复制代码


parentHashtransactionsRoot 分别对应着 Bitcoin 中 previousblockhashmerkleroot,这两者在整个区块链网络中是非常重要的。

哈希指针

Block 结构体中的哈希指针在区块链中有两个作用,它不仅能够连接不同的区块,还能够对 Block 进行验证,保证 Block 中的数据不会被其他恶意节点篡改。



除了第一个 Block,每一个 Block 中的 prev_hash 都是前一个 Block 的哈希,如果某一个节点想要修改主链上 Block 的交易,就会改变当前 Block 的哈希,后面的 Block 就没有办法通过 prev_hash 找到前面的链,所以当前节点篡改交易的行为就会被其他节点发现。

Merkle Tree

另一个字段 merkleroot 其实就是一个 Merkle 树 的根节点,它其实是一种使用哈希指针连接的数据结构;虽然 Merkle 树有叶节点和非叶节点,但是它只有叶节点会存储数据,所有的非叶结点都是用于验证数据完整性的哈希。



每一个 Block 中的全部交易都是存储在这个 Merkle 树中并将 merkleroot 保存在 Block 的结构体中,保证当前 Block 中任意交易的篡改都能被立刻发现。

小结

prev_hashmerkleroot 分别通过『指针』的方式保证所有的 Block 和交易都是连接起来的,最终保证 Block 和交易不会被恶意节点或攻击者篡改,几乎全部的区块链项目都会使用类似方式连接不同的 Block 和交易,这可以说是区块链项目的基础设施和标配了。

UTXO 模型

作为最早出现的加密货币,Bitcoin 就采用了 UTXO 模型作为其底层存储的数据结构,其全称为 Unspent Transaction output,也就是未被使用的交易输出。


在 Bitcoin 以及其他使用 UTXO 模型的加密货币中,某一个『账户』中的余额并不是由一个数字表示的,而是由当前区块链网络中所有跟当前『账户』有关的 UTXO 组成的。



上图中所有绿色的交易输出才是 UTXO,红色的交易输出已经被当前『账户』使用了,所以在计算当前账户的余额时只会考虑绿色的交易输出,也就是 UTXO。


JavaScript


{   "addr":"14uhqGYDEhqwfdoP59QdLWdt4ha5CHttwQ",   "n":1,   "script":"76a9142ae017a5bd24a3f935897085253e503fbfd66f4e88ac",   "spent":false,   "tx_index":335926477,   "type":0,   "value":21680000}
复制代码


上述的 UTXO 中包含了很多信息,例如:包含当前 UTXO 属于的交易索引 tx_index、交易接收方的地址 addr、交易的数额 value

交易

UTXO 其实就是交易的一部分,基于 UTXO 模型的交易由输入和输出两个部分组成:


JavaScript


{   "txid":"5be7a9e47f56c98e5297a44df52da0475f448ece98bb51489103cdf70653092f",   "hash":"5be7a9e47f56c98e5297a44df52da0475f448ece98bb51489103cdf70653092f",   "version":1,   "size":224,   "vsize":224,   "locktime":0,   "vin": [...],   "vout": [...],   "hex":"0100000001a90b4101e6cbb75e1ff885b6358264627581e9f96db9ae609acec98d72422067000000006b483045022100c42c89eb2b10aeefe27caea63f562837b20290f0a095bda39bec37f2651af56b02204ee4260e81e31947d9297e7e9e027a231f5a7ae5e21015aabfdbdb9c6bbcc76e0121025e6e9ba5111117d49cfca477b9a0a5fba1dfcd18ef91724bc963f709c52128c4ffffffff02a037a0000000000017a91477df4f8c95e3d35a414d7946362460d3844c2c3187e6f6030b000000001976a914aba7915d5964406e8a02c3202f1f8a4a63e95c1388ac00000000",   "blockhash":"0000000000000000000c23ca00756364067ce5e815deb5982969df476bfc0b5c",   "confirmations":5,   "time":1521981077,   "blocktime":1521981077}
复制代码


交易对象中的大多数其它字段并没有什么意义,只是对当前的交易进行了一些描述,让我们能够更好的理解当前交易的相关信息,例如:上述交易中的 sizevsize 字段可以从交易其他部分计算出来。


在每一笔合法的交易中,所有的输入的 value 之和必须大于所有输出的 value 之和,这两者之间的差值就是矿工费:


sum(inputs.value) = sum(outputs.value) + fee
复制代码


基于 UTXO 的交易模型,与我们在日常生活中使用纸币的场景是非常相似的,每一张纸币都是不可分割的整体,当我们想要使用现金购买商品或者服务时,往往都会获得找零


inputs = price + change + fee
复制代码


每一个 UTXO 和纸币一样,只可能有两种状态,要么是没有被花费的,要么就是已经被花费,所有权变成了其他人或者地址,成为其他地址的 UTXO。



在基于 UTXO 的区块链网络中,除了找零(Change)非常常见之外,将多个 UTXO 整合(Consolidate)成一个 UTXO 的操作也比较常见,在 Bitcoin 的网络中,无论当前的 UTXO 中有多少钱,每一个 UTXO 的大小都是差不多的,所以在进行大额转账时,往往需要多个 UTXO 作为输入,这样会明显的增加交易的矿工费。

输入和签名

UTXO 模型中的每一笔交易都是由多个交易输入组成的,这些输入其实就是 UTXO + 签名:


JavaScript


{   "vin":[      {         "txid":"672042728dc9ce9a60aeb96df9e9817562648235b685f81f5eb7cbe601410ba9",         "vout":0,         "scriptSig":{            "asm":"3045022100c42c89eb2b10aeefe27caea63f562837b20290f0a095bda39bec37f2651af56b02204ee4260e81e31947d9297e7e9e027a231f5a7ae5e21015aabfdbdb9c6bbcc76e[ALL] 025e6e9ba5111117d49cfca477b9a0a5fba1dfcd18ef91724bc963f709c52128c4",            "hex":"483045022100c42c89eb2b10aeefe27caea63f562837b20290f0a095bda39bec37f2651af56b02204ee4260e81e31947d9297e7e9e027a231f5a7ae5e21015aabfdbdb9c6bbcc76e0121025e6e9ba5111117d49cfca477b9a0a5fba1dfcd18ef91724bc963f709c52128c4"         },         "sequence":4294967295      }   ]}
复制代码


上述 JSON 其实就是 Bitcoin 交易 #338309214 的输入,这里的 prev_out 就来自于另一笔交易 #338283541 的输出,通过不停的回溯,最终我们会找到当前交易涉及的 Coinbase,也就是当前 UTXO 相关 Bitcoin 被挖出来的 Block 的首笔交易。


通过 txidvout 两个字段,我们能够在区块链网络中定位到唯一一个 UTXO,这个 UTXO 加上持有当前 UTXO 的地址对交易的签名构成了一个交易输入。

输出

每一个交易都可能会有多个输出,也就是 vout 数组,每一个 vout 都可以指向不同的地址,其中也有当前输出包含的值 value,在这里也就是 Bitcoin 的单位:


JavaScript


{   "vout":[      {         "value":0.10500000,         "n":0,         "scriptPubKey":{            "asm":"OP_HASH160 77df4f8c95e3d35a414d7946362460d3844c2c31 OP_EQUAL",            "hex":"a91477df4f8c95e3d35a414d7946362460d3844c2c3187",            "reqSigs":1,            "type":"scripthash",            "addresses":[               "3CcqrGq4oQcfx3u75ijj4tDiqf4HJvhoeP"            ]         }      },      {         "value":1.84809190,         "n":1,         "scriptPubKey":{            "asm":"OP_DUP OP_HASH160 aba7915d5964406e8a02c3202f1f8a4a63e95c13 OP_EQUALVERIFY OP_CHECKSIG",            "hex":"76a914aba7915d5964406e8a02c3202f1f8a4a63e95c1388ac",            "reqSigs":1,            "type":"pubkeyhash",            "addresses":[               "1GedHcxdxq2tab98hqAmREUK9BBYHKznof"            ]         }      }   ]}
复制代码


每一个未被使用的 vout 就是一个 UTXO(Unspent Transaction Output),我们可以通过其中的 addresses 字段找到持有当前输出的地址。

小结

UTXO 模型通过链式的方式组织所有交易的输入和输出,每一个交易的输出最终都能追寻到一个 Coinbase,也就是当前 Bitcoin 被挖出时的区块的第一笔交易。



由于在 UTXO 中没有账户的概念,所以并行地处理交易不会出现任何问题,同时不可变的账本能够让我们在 Bitcoin 节点快速更新时,也能分析某一时刻整个网络中数据的快照。


虽然 UTXO 模型的不可变账本条目带来一些好处,但是当我们需要计算某个地址中的余额时,需要遍历整个网络中的全部相关区块,同时,并行的处理交易虽然可行,不过并行的创建交易却会出现很多问题,例如多笔交易使用了同一个 UTXO,导致双花,最终只有一笔交易能够被网络确认。


UTXO 模型确实能够解决区块链世界中的各种问题,它的核心思想就是保证已经写入的数据不可变,链式的 UTXO 就是基于这一核心思想的,通过哈希指针连接不同交易的输入和输出,保证所有交易的合法性。

账户余额模型

与 UTXO 模型不同的就是账户余额模型,它跟现实世界中的银行账户非常相似,Ethereum 就使用了账户余额模型存储区块链中的数据。



相比于 UTXO 模型,账户余额模型更加容易实现和理解,如果忽略很多 Ethereum 的实现细节,那么在整个网络中只存在三种对象:账户、交易和区块。在这里,我们会介绍该模型中的三个最重要的概念,虽然 Block 并不是账户余额模型中独有的概念,但是我们也会介绍它在 Ethereum 中有什么特殊之处。

账户

Ethereum 其实就是一个巨大的状态机,其中的状态都是由多个账户组成的,每一个账户都包含四个字段 (nonce, ether_balance, contact_code, storage)



在 Ethereum 中有两种类型的账户,一种是被私钥控制的账户,它没有任何的代码,与 Bitcoin 地址基本有完全相同的功能,能够向网络中发送已签名的交易;另一种是被合约代码控制的账户,能够在每一次收到消息时,执行保存在 contract_code 中的代码,所有的合约在网络中都能够响应其他账户的请求和消息并提供一些服务。


所有账户的 nonce 都必须从 0 开始递增,当前账户每使用 nonce 签发并广播一笔交易之后,都会将其 +1;UTXO 模型决定了来自同一地址的多笔金额相同的交易完全不同,从原理上避免了重放攻击,因为账户余额模型中不存在 UTXO,交易仅仅是账户 ether_balance 的变动,所以在这里引入 nonce 来解决重放攻击的问题。

合约账户

被私钥控制的账户与 Bitcoin 中地址其实差不多,所以没有什么可以解释的,这里简单介绍一些合约账户。目前 Ethereum 网络上最多的合约账户应该就是 ERC20 的合约了,我们平时经常说的 Token 就是 Ethereum 上的合约,这些合约其实也是 Ethereum 账户:


C


contract ERC20Interface {    function totalSupply() public constant returns (uint);    function balanceOf(address tokenOwner) public constant returns (uint balance);    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);    function transfer(address to, uint tokens) public returns (bool success);    function approve(address spender, uint tokens) public returns (bool success);    function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed tokenOwner, address indexed spender, uint tokens);}
复制代码


Token 的转账其实就是合约的调用,所有的账户余额都是存储在这个合约的 balances 中:


C


mapping(address => uint256) balances;
复制代码


每一笔 Token 的转账都会改变这个 mapping 中对应地址的值并发出 Transfer 事件,这也就是 Token 的实现原理;部署 Token 的智能合约其实非常简单,很多加密货币项目其实都只是一个 ERC20 的 Token,发行的成本几乎为 0。

交易

由于没有 Bitcoin 复杂的 UTXO 模型,Ethereum 的交易模型也简单,交易中没有输入和输出的 TransactionIO 结构,只有 fromto 两个地址:


JavaScript


{   "blockHash":"0xb4a992ff99a487db8421f516be998920f06dfe5d355d88e3b7f22b7422e6340d",   "blockNumber":"0x24f85c",   "chainId":null,   "condition":null,   "creates":null,   "from":"0x8b56adcf332ff80a1f1bf433975dcb28b730d110",   "to":"0xe94b04a0fed112f3664e45adb2b8915693dd5ff3",   "value":"0x10d43fb8311ca800",   "gas":"0x2062a",   "gasPrice":"0x560aab7c5",   "hash":"0xfea448d11cfa863c8b3c38d3b65649e66c1957f9ac16638e3a0edff45a6b3d84",   "input":"0x0f2c9329000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98000000000000000000000000e592b0d8baa2cb677034389b76a71b0d1823e0d1",   "nonce":"0x3fe",   "publicKey":"0x765b0f012e49f6a4cc5c917fb176984b24814bdaf5f9464db1a7f9ffcc730cb678f69e49f78aa9de8249cce138bbc25cf8842374d8d09089dff7f1ef6906f4fb",   "r":"0x4275d35821dec971f6d58c2adae077ffcdfa3ec74af542a2d29ab4e5239d8b25",   "raw":"0xf8b48203fe850560aab7c58302062a94e94b04a0fed112f3664e45adb2b8915693dd5ff38810d43fb8311ca800b8440f2c9329000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98000000000000000000000000e592b0d8baa2cb677034389b76a71b0d1823e0d11ca04275d35821dec971f6d58c2adae077ffcdfa3ec74af542a2d29ab4e5239d8b25a036221b525c758c45e60f964eec698ae33208dfa74bea7f77dff002ceec418b0a",   "s":"0x36221b525c758c45e60f964eec698ae33208dfa74bea7f77dff002ceec418b0a",   "standardV":"0x1",   "transactionIndex":"0x8",   "v":"0x1c"}
复制代码


交易的手续费也不再是交易输入输出 value 的差值,而是使用 gasgasPrice 来表示,为了防止重放攻击,这里也引入了 nonce 字段。



(nonce, from, to, value, input) 是一个 Transaction 包含的最重要的几个字段,通过 nonce 防止重放攻击,fromto 分别表示了当前交易的发出者和接受者,value 是当前交易包含的 Etherinput 中包含了合约调用相关的二进制信息。


每当一个 Transaction 被 Ethereum 主网挖到后,fromto 账户的 Ether 余额就会变动,Ethereum 就像一个状态机,它接受一个又一个的 Transaction 并不停改变自己的状态。


小结

账户余额模型是一种非常容易理解的区块链应用模型,它与我们生活中的账户模型非常相似,只是为了保证账户的安全,使用了签名以及 nonce 的机制阻止恶意的攻击。这种基于账户余额模型的应用包含了一个包含所有账户余额的全局状态,在进行转账时,需要由节点对账户的余额进行验证,判断当前账户是否有足够的 Ether 进行转账。

总结

无论是 UTXO 模型还是账户余额模型,都能够很好地解决区块链世界中的『安全』问题,保证交易的合法,从原理上杜绝一些可能的攻击行为,实现原理的不同其实也只是由于出发点不同,在设计时权衡了利弊;UTXO 模型相比于账户余额模型有以下的两个优点:


  • 如果用户启用了新的地址用于转账和交易,新地址与原地址之间的关系很难被追踪,更好地保证用户的隐私;

  • UTXO 模型理论上来说可以并行地利用不同的 UTXO 签发多笔交易,并广播到网络中;


而账户余额模型也有它的优点:


  • 非常容易理解和编码实现;

  • 每一笔交易都只需要有一个签名,交易的输入和输出都是地址,能够节省存储空间;

  • 由于在区块链层级没有『币的来源』这一概念,很难实现对来源的追踪和回溯;

  • 因为创建交易时不需要对过去的 UTXO 进行签名,可以从任何一个时间点开始同步区块的状态,利于编写轻量级客户端;


总而言之,软件开发到最后就是进行权衡的过程,选择一些优势必然会在另外一些领域上处于劣势,如何在不同的需求进行权衡是开发区块链应用以及所有应用都需要考虑的事情。

Reference


本文转载自 Draveness 技术博客。


原文链接:https://draveness.me/utxo-account-models


2019-12-05 18:171215

评论

发布
暂无评论
发现更多内容

聊聊技术变现这件事

老张

斜杠青年 技术变现 技术咨询

Vue3 修改项目名称及相关信息

Andy

瓴羊Quick BI连续四年入选Gartner魔力象限ABI报告

流量猫猫头

Auto-GPT 迈向智能体的第一步——从信息增强和上下文理解开始

Zilliz

Milvus 向量数据库 autogpt gptcache zillizcloud

CMake vs Makefile: 如何选择适合你的项目构建工具

小万哥

Linux 程序员 C/C++ 后端开发 cmake

设计模式之订阅发布模式

越长大越悲伤

设计模式 发布订阅模式 spring boot3 订阅发布

关于斐波那契数列的笔记

贝湖光

Go 语言 map 是并发安全的吗?

AlwaysBeta

Go 面试 map

牧云 • 主机管理助手|正式开放应用市场,梦幻联动雷池WAF等多款开源软件

百川云开发者

云计算 防火墙 云主机 waf 主机管理

极光笔记 | EngageLab Push的多时区解决方案

极光JIGUANG

运营 消息推送 笔记分享 海外

神册!出自阿里P8的深入理解Java虚拟机最新版,让我涨薪60%

Java你猿哥

Java JVM 虚拟机 并发 代码优化

多模块更新,助力模型训练及应用|ModelWhale 版本更新

ModelWhale

人工智能 云计算 数据标注 在线编程 模型服务

Zebec生态进展迅速,频被BitFlow、Matryx DAO等蹭热度碰瓷

鳄鱼视界

安全可信 | 增强级认定!天翼云政务云通过云计算服务安全评估

天翼云开发者社区

云服务 服务器安全

PoseiSwap 参赛,参与斯坦福、Nautilus等联合主办的 Hackathon 活动

西柚子

世界顶级级架构师编写2580页DDD领域驱动设计笔记,属实有牌面

Java你猿哥

Java 领域驱动设计 DDD crud 领域驱动

C语言编程—作用域规则

梦笔生花

AIGC背后的技术分析 | 机器学习背后的微分入门

TiAmo

机器学习 AIGC

MySQL 正确使用带有横线“-”SQL语句

Andy

2023-05-26:golang关于垃圾回收和析构函数的选择题,多数人会选错。

福大大架构师每日一题

golang 福大大

改变开发的未来 | 探索无服务器与人工智能的协同效应

亚马逊云科技 (Amazon Web Services)

Serverless

Django笔记三十七之多数据库操作(补充版)

Hunter熊

Python django 多数据库

PoseiSwap 参赛,参与斯坦福、Nautilus等联合主办的 Hackathon 活动

BlockChain先知

九章云极DataCanvas公司诚邀您共享AI基础软件前沿技术盛宴

九章云极DataCanvas

数字化转型应该如何去做?(敏捷思维篇)

数字随行

数字化转型

点云标注简介及其应用

来自四九城儿

ESG成全球风潮,联想造了一个可持续的“进托邦”

脑极体

数字化进程

PoseiSwap  参赛,参与斯坦福、Nautilus Chain等联合主办的 Hackathon 活动

股市老人

一文看懂GPT风口,都有哪些创业机会?

引迈信息

人工智能 低代码 ChatGPT JNPF gtp

云服务器虚拟化超分与虚机性能关系分析

天翼云开发者社区

云服务器 虚拟化技术

UTXO 与账户余额模型_语言 & 开发_Draveness_InfoQ精选文章