详解以太坊默克尔压缩前缀树-MPT

发表于 5年以前  | 总阅读数:3135 次

在以太坊中,一种经过改良的默克尔树非常关键,是以太坊数据安全与效率的保障,此树在以太坊中称之为 MPT(默克尔压缩前缀树)。 MPT 全称是 Merkle Patricia Trie 也叫 Merkle Patricia Tree,是 Merkle Tree 和 Patricia Tree 的混合物。 Merkle Tree(默克尔树) 用于保证数据安全,Patricia Tree(基数树,也叫基数特里树或压缩前缀树) 用于提升树的读写效率。

简述

以太坊不同于比特币的 UXTO 模型,在账户模型中,账户存在多个属性(余额、代码、存储信息),属性(状态)需要经常更新。因此需要一种数据结构来满足几点要求:

  • ①在执行插入、修改或者删除操作后能快速计算新的树根,而无需重新计算整个树。
  • ②即使攻击者故意构造非常深的树,它的深度也是有限的。否则,攻击者可以通过特意构建足够深的树使得每次树更新变得极慢,从而执行拒绝服务攻击。
  • ③树的根值仅取决于数据,而不取决于更新的顺序。以不同的顺序更新,甚至是从头重新计算树都不会改变树的根值。

要求①是默克尔树特性,但要求②③则非默克尔树的优势。 对于要求②,可将数据 Key 进行一次哈希计算,得到确定长度的哈希值参与树的构建。而要求③则是引入位置确定的压缩前缀树并加以改进。

Trie 介绍

对部分开发者来说 Trie 这个术语可能比较陌生,而理解 Trie 的概念在本文中非常重要。因此,我先介绍 Trie 。

在计算机科学中, Trie ,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。 与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。 一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。 一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

Trie 这个术语来自于re Trie val。根据词源学, Trie 的发明者Edward Fredkin把它读作/ˈtriː/ "tree"。但是,其他作者把它读作/ˈtraɪ/ "try"。如图所示:

以太坊技术与实现-图2019-11-17-22-25-43

在图示中,键标注在节点中,值标注在节点之下。每一个完整的英文单词对应一个特定的整数。 Trie 可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的。键不需要被显式地保存在节点中。图示中标注出完整的单词,只是为了演示 Trie 的原理。

Trie 中的键通常是字符串,但也可以是其它的结构。 Trie 的算法可以很容易地修改为处理其它结构的有序序列,比如一串数字或者形状的排列。比如,bitwise Trie 中的键是一串比特,可以用于表示整数或者内存地址。

上文摘自维基百科。

压缩前缀树(Patricia Tree)

压缩前缀树(基数树)中,键值是通过树到达相应值的实际路径值。 也就是说,从树的根节点开始,键中的每个字符会告诉您要遵循哪个子节点以获取相应的值,其中值存储在叶节点中,叶节点终止了穿过树的每个路径。假设键是包含 N 个字符的字母,则树中的每个节点最多可以有 N 个子级,并且树的最大深度是键的最大长度。

以太坊技术与实现-图2019-11-17-23-24-32

虽然基数树使得以相同字符序列开头的键的值在树中靠得更近,但是它们可能效率很低。 例如,当你有一个超长键且没有其他键与之共享前缀时,即使路径上没有其他值,但你必须在树中移动(并存储)大量节点才能获得该值。 这种低效在以太坊中会更加明显,因为参与树构建的 Key 是一个哈希值有 64 长(32 字节),则树的最长深度是 64。树中每个节点必须存储 32 字节,一个 Key 就需要至少 2KB 来存储,其中包含大量空白内容。 因此,在经常需要更新的以太坊状态树中,优化改进基数树,以提高效率、降低树的深度和减少 IO 次数,是必要的。

改进方案

为了解决基数树的效率问题,以太坊对基数树的最大改动是丰富了节点类型,围绕不同节点类型的不同操作来解决效率。

  1. 空白节点 NULL
  2. 分支节点 branch Node [0,1,...,16,value]
  3. 叶子节点 leaf Node : [key,value]
  4. 扩展节点 extension Node: [key,value]

多种节点类型的不同操作方式,虽然提升了效率,但复杂度被加大。而在 geth 中,为了适应实现,节点类型的设计稍有不同:

//trie/node.go:35
type (
    fullNode struct { //分支节点
        Children [17]node
        flags    nodeFlag
    }
    shortNode struct { //短节点:叶子节点、扩展节点
        Key   []byte
        Val   node
        flags nodeFlag
    }
    hashNode  []byte //哈希节点
    valueNode []byte //数据节点,但他的值就是实际的数据值
)
var nilValueNode = valueNode(nil) //空白节点
  • fullNode: 分支节点,fullNode[16]的类型是 valueNode。前 16 个元素对应键中可能存在的一个十六进制字符。如果键[key,value]在对应的分支处结束,则在列表末尾存储 value 。
  • shortNode: 叶子节点或者扩展节点,当 shortNode.Key的末尾字节是终止符 16 时表示为叶子节点。当 shortNode 是叶子节点是,Val 是 valueNode。
  • hashNode: 应该取名为 collapsedNode 折叠节点更合适些,但因为其值是一个哈希值当做指针使用,所以取名 hashNode。使用这个哈希值可以从数据库读取节点数据展开节点。
  • valueNode: 数据节点,实际的业务数据值,严格来说他不属于树中的节点,它只存在于 fullNode.Children 或者 shortNode.Val 中。

各类 Key

在改进过程中,为适应不同场景应用,以太坊定义了几种不同类型的 key 。

  1. keybytes :数据的原始 key
  2. Secure Key: 是 Keccak256(keybytes) 结果,用于规避 key 深度攻击,长度固定为 32 字节。
  3. Hex Key: 将 Key 进行半字节拆解后的 key ,用于 MPT 的树路径中和降低子节点水平宽度。
  4. HP Key: Hex 前缀编码(hex prefix encoding),在节点存持久化时,将对节点 key 进行压缩编码,并加入节点类型标签,以便从存储读取节点数据后可分辨节点类型。

下图是 key 有特定的使用场景,基本支持逆向编码,在下面的讲解中 Key 在不同语义下特指的类型有所不同。 图:以太坊 MPT 中几类 Key

节点结构改进

当我们把一组数据(romane、romanus、romulus、rubens、ruber、rubicon、rubicunds)写入基数树中时,得到如下一颗基数树:

在上图的基数树中,持久化节点,有 13 次 IO。数据越多时,节点数越多,IO 次数越多。另外当树很深时,可能需要遍历到树的底部才能查询到数据。 面对此效率问题,以太坊在树中加入了一种名为分支节点(branch node) 的节点结构,将其子节点直接包含在自身的数据插槽中。

这样可缩减树深度和减少IO次数,特别是当插槽中均有子节点存在时,改进效果越明显。 下图是上方基数树在采用分支节点后的树节点逻辑布局:

从图中可以看出节点数量并无改进,仅仅是改变了节点的存放位置,节点的分布变得紧凑。图中大黑圆圈均为分支节点,它包含一个或多个子节点, 这降低了 IO 和查询次数,在上图中,持久化 IO 只有 6 次,低于基数树的 12 次。

这是因为在持久化分支节点时,并不是将叶子节点分开持久化,而是将其存储在一块。并将持久化内容的哈希值作为一个新节点来参与树的进一步持久化,这种新型的节点称之为扩展节点。比如,数据 rubicon(6) 和 rubicunds(7) 是被一起持久化,在查询数据 rubicon 时,将根据 hasNode 值从数据库中读取分支节点内容,并解码成分支节点,内含 rubicon 和 rubicunds。

另外,数据 Key 在进入 MPT 前已转换 Secure Key。 因此,key 长度为 32 字节,每个字节的值范围是[0 - 255]。 如果在分支节点中使用 256 个插槽,空间开销非常高,造成浪费,毕竟空插槽在持久化时也需要占用空间。同时超大容量的插槽,也会可能使得持久化数据过大,可能会造成读取持久化数据时占用过多内存。 如果将 Key 进行Hex 编码,每个字节值范围被缩小到 [0-15] 内(4bits)。这样,分支节点只需要 16 个插槽来存放子节点。

上图中 0 - f 插槽索引是半字节值,也是 Key 路径的一部分。虽然一定程度上增加了树高,但降低了分支节点的存储大小,也保证了一定的分支节点合并量。

树的增删改查

上面已介绍树的改进内容,下面我们来讲解经过改进后,树的增删改查将有哪些不一样。在讲解前需要你掌握几个内含的规则和概念:

  1. MPT 是一颗逻辑树,并不一一对应物理树(存储)。
  2. 在 MPT 中必将在叶子节点处存放在 Key 对应的数据节点(ValueNode),数据节点必然是在树的子叶节点中。
  3. 在 MPT 中,到达节点的树路径 Path 和节点中记录的 Key 一起构成了节点的完整 Key。
  4. 分支节点的插槽 Index 就是树路径的一部分。

查询数据

即使在修改某项数据时,也会涉及到查询,因此我先讲讲 MPT 树的查询逻辑。 在树中查找数据,需要考虑性能,省时和低 IO 是关键。 因为数据项 [Key,Value] 的 Key 是确定的,那么数据在 MPT 中的树路径也是确定的。 因此,达到数据项的路径是唯一的,是效率最高的最短路径查找。

下图是以太坊从 MPT 中查询查找某 Key 对应数据的流程图。

以太坊技术与实现-图-以太坊从 MPT 中查询查找某 Key 对应数据的流程图

图中流程中,有几点需要稍微说明:

  1. 查找时依赖节点的类型,不同类型的节点所包含的值属性不同。
  2. 要找的数据虽然并不一定对应一个存储,但要查找的数据存在于叶子节点的 shortNode.Value 中,value 实际 valueNode 。
  3. 在分支节点中继续向下查找时,分支节点的子节点插槽也属于路径的一部分,占用一个字节。根据 pos= key[0] 便可在确定的插槽 pos 中继续查找。
  4. 短节点 shortNode [key,value] 中只有在 数据 key 是 node.key 的前缀时,才能说明数据项属于 node 子树的一部分,可以继续查找。
  5. 当节点是哈希节点时,node 就是节点数据持久化到 KV 数据库时所用的键。根据此键可以从数据库中读取节点原始数据。加载节点数据到内存后,可以继续判断节点类型。

插入数据

插入数据包含新数据加入和旧数据修改。下图是往 MPT 中插入数据流程。

以太坊技术与实现-图-往 MPT 中插入数据

首先,插入空节点是无意义的,反而会使树变得臃肿。 因此,当数据为空时,需从树中删除该数据节点。 否则需要根据数据节点的路径从树根开始查找到数据节点所在位置来更新节点。在查找时根据路径中节点的类型不同,需要不同的解析方式。

  1. 判断当前节点的类型,如果是哈希节点,则需要先从数据库中读取节点原始数据。还原成一颗子树后,继续执行插入到此子树中。
  2. 如果是分支节点,那么只需要确认子节点插槽位置,便可以将子节点作为一颗子树继续下探尝试更新。
  3. 如果是短节点,则需匹配相同前缀。如果前缀刚好等于原节点key,则说明需要将原节点的 value 进行更新。 否则,说明此路径处需要分叉才能容纳这个两个节点。分叉时,是构建新的分支节点,新节点的 key 为相同前缀部分,将原节点下移到新节点下对应的子节点插槽中。 数据节点则也存放在新节点对应的插槽中。
  4. 当到达数据节点时,数据节点的 Key 是不存在的,节点本身即是数据。如果节点不含数据,则说明插入的节点是第一次出现,属于新增。在树中加入此数据节点即可。 如果存在数据,则说明属于更新旧数据,覆盖即可。

插入数据的过程,是深度递归遍历方式。先深度查找,抵达数据应处位置,再从下向上依次更新此路径上的节点。 虽然只更新了路径中的相关节点,但这毕竟涉及多个节点的更新。从这一点上看,MPT 性能并不出色。

以太坊技术与实现-图-以太坊 MPT 树操作时的递归

删除数据

从 MPT 中删除数据节点,这比插入数据更加复杂。从树中删除一个节点是容易的,但在 MPT 中删除节点后需要根据前面的改进方案调整结构。 比如,原本是一个分支节点下有两个子节点,现在删除一个子节点后,只有一个子节点的分支节点的存储是无意义的,需要移除并将剩余的子节点上移。 下图是 MPT 中删除数据的流程图。

以太坊技术与实现-图- MPT中删除数据的流程图 同样,删除数据也是深度递归遍历。先深度查找,抵达数据应处位置,再从下向上依次更新此路径上的节点。 在删除过程中,主要是对删除后节点的调整。有两个原则:

  1. 分支节点至少要有两个子节点,如果只有一个子节点或者没有则需要调整。
  2. shortNode 的 value 是 shortNode 时可合并。

删除数据也涉及路径上节点的更新,图中的绿色虚线是表示递归删除节点。

树更新实例

下面,我演示依次将一组数据 romane、romanus、romulus、rubens、ruber、rubicon、rubicunds 插入到 MPT 中时的树结构的变化情况。

首先依次写入:romane、romanus、romulus 后树的变化如下:

以太坊技术与实现-图-20191127165135.png

图中的每一个圆圈均代表一个节点,只是节点的类型不同。需要注意的是,图中的红色字部分,实际是一个短节点(shortNode)。 比如,红色的“roman“ 短节点的 key 为 roman, value 是分支节点。继续写入 rubens、ruber、rubicon 的变化过程如下:

以太坊技术与实现-图-20191127165900.png

最后,写入最后一个数据项 rubicunds 后可得到最终的 MPT 树结构:

以太坊技术与实现-图-20191127170214.png

注意,本过程演示中,为降低复杂度,省去了 key 的 Secure 和 Hex 过程。

MPT数操作总结

即使以太坊有大量改进基数树,形成 MPT。但还是并没有解决树节点更新时的蝴蝶效应问题。 在 MPT 中树的最大深度是 64,当树充分大时,为更新一个数据节点而需要连带更新的节点也非常多。 这使得以太坊的数据更新是昂贵的。大量的变动也会使得每产生一个新区块,持久化数据后。 有大量的存储不再属于最新状态的一部分,即以太坊的数据增量更新的体量依旧很大。

如果要满足以太坊 2.0 的性能要求,继续改进 MPT 是不可忽略的。

计算树Root

上面已描述 MPT 在内存中的结构,下面我们以 romane、romanus、romulus 为示例数据,来讲解是何如计算出 MPT 树的一个树根 Root 值的。

以太坊技术与实现-以太坊 MPT 树结构布局示例

上图是三项数据的业务 Key 经过 HP 编码后,写入 MPT 树后所形成的 MPT 树结构布局。HP表和树的虚线连接表示树路径的生成依据,这是根据前面所描述的 MPT 生成规则而形成的树结构。在树中,一共有6 个节点,其中节点 1 和 3 为扩展节点,节点 2 和 5 为分支节点,节点 4 和 6 为叶子节点。可以看到在分支节点 5 中的 value 位置存放着业务 key “romane” 所对应的值“罗马”,但业务 key “romanus”和“romulus” 则存放在独立的叶子节点中。

当我们执行 trie.Commit 时将获得一个 Hash 值,称之为 树的 Root 值,这个 Root 值是如何得到的呢? Root 值算法源自默克尔树(Merkle Tree),在默克尔树中,树根值是由从子叶开始不断进行哈希计算得到最终能代表这棵树数据的哈希值。

以太坊技术与实现-图-默克尔树

同样在计算 MPT 树的 Root 值是也是如此,在 MPT 中一个节点的哈希值,是节点内容经 RLP 编码后的 Keccak256 哈希值。当对一个节点进行哈希计算遵循如下规则:

  1. Hash(扩展节点)= Hash( HP(node.Key),Hash(node.Value) ), 节点 key 需 HP 编码后参与哈希计算。当 node.Value 是表示业务数据时(valueNode),将为 Hash( HP(node.Key),node.Value)。
  2. Hash(叶子节点) 无,叶子节点只存在于分支节点中。
  3. Hash(分支节点)= Hash( hash(node.Children[1]),...,hash(node.Children[i]),node.Value),需要先将每个子节点存储中的节点进行哈希。如果子节点为 null,则使用空字节表示。

根据上面的规则,我们可以得到上面 MPT 树进行哈希计算时的节点分布:

以太坊技术与实现-图-以太坊 MPT 树的哈希计算

图中,可哈希的节点只有 4 个,而叶子节点 4 和 6 则直接属于分支节点的一部分参与哈希计算。MPT 的 Root 值是 MPT 树根节点的哈希值。在本示例中,Root 节点为 节点 1,Hash(节点 1)=0x84f3c5......80ef13 即为 MPT 的 Root 值。扩展节点 1 和 3 的 key 在哈希计算时有进行 HP 编码。需要编码的原因是为了区分扩展节点的 value 是叶子节点还是分支节点的区别,具体见 HP 编码规则

持久化

当需要将 MPT Commit 到 DB 时,这颗树的数据是如何完整存储到数据库的呢?以太坊的持久层是 KV 数据库,一个 Key 对应一份存储内容。 当上面在计算 Root 值时,实际上已完成了哈希值和节点内容的处理过程。不同于在内存中计算 Root 值,在持久化时是持久化和 Hash 计算同步进行。

从Root的计算规则可知,HASH 计算是递归的,从树的叶子节点向上计算。每次计算出一个节点哈希时,将使用此哈希值作为数据库的 Key,存放节点的 RLP 持久化内容到数据库中。 因为节点哈希值以及被包含在父节点中,直至树根。因此,我们只需要知道一颗树的 Root 值,便可以依次从 DB 中读取节点数据,并在内存中构建完整的 MPT 树。

比如,上图中的树的 Root 值为 0x84f3c5……80ef13,通过 db.Get(root) 可获得节点 1,在通过 db.Get(node1.Value) 可获得节点 2...,直至节点 5。

需要注意的是,在分支节点 2 中,他的子节点插槽 6 的位置上是记录的节点 3 的哈希值。在从数据库中获得节点 2 时,并不会立刻将 节点 3 立刻加载。而是在需要使用 到 node2.Children[6]时,根据 node2.Children[6].Value 的类型仅一步判断。如果它是 hashNode 类型,则将根据此 Value 获取节点数据并展开。这样,保证在使用树时是按需实例化节点。

Key的编码规则

Secure 编码

这并非 MPT 树的必要部分,是为了解决路径深度攻击而将数据进入 MPT 前进行一次安全清洗,使用 Keccak256(key) 得到的key 的哈希值替换原数据 key。

在实现上,只需要在原 MPT 树进行依次封装即可获得一颗 Secure MPT 树。

HEX 编码

用于树路径中,是将数据 key 进行半字节拆解而成。即依次将 key[0],key[1],...,key[n] 分别进行半字节拆分成两个数,再依次存放在长度为 len(key)+1 的数组中。 并在数组末尾写入终止符 16。算法如下:

半字节,在计算机中,通常将8位二进制数称为字节,而把4位二进制数称为半字节。 高四位和低四位,这里的“位”是针对二进制来说的。比如数字 250 的二进制数为 11111010,则高四位是左边的 1111,低四位是右边的 1010。

// trie/encoding.go:65
func keybytesToHex(str []byte) []byte {
    l := len(str)*2 + 1
    var nibbles = make([]byte, l)
    for i, b := range str {
        nibbles[i*2] = b / 16
        nibbles[i*2+1] = b % 16
    }
    nibbles[l-1] = 16
    return nibbles
}

例如:字符串 “romane” 的 bytes 是 [114 111 109 97 110 101],在 HEX 编码时将其依次处理:

i key[i] key[i]二进制 nibbles[i*2]=高四位 nibbles[i*2+1]=低四位
0 114 011100102 01112= 7 00102= 2
1 111 011011112 01102=6 11112=15
2 109 011011012 01102=6 11012=13
3 97 011000012 01102=6 00012=1
4 110 011011102 01102=6 11102=14
5 101 011001012 01102=6 01012=5

最终得到 Hex("romane") = [7 2 6 15 6 13 6 1 6 14 6 5 16]

HP(Hex-Prefix) 编码

Hex-Prefix 编码是一种任意量的半字节转换为数组的有效方式,还可以在存入一个标识符来区分不同节点类型。 因此 HP 编码是在由一个标识符前缀和半字节转换为数组的两部分组成。存入到数据库中存在节点 Key 的只有扩展节点和叶子节点,因此 HP 只用于区分扩展节点和叶子节点,不涉及无节点 key 的分支节点。其编码规则如下图:

以太坊技术与实现-以太坊 HP 编码规则

前缀标识符由两部分组成:节点类型和奇偶标识,并存储在编码后字节的第一个半字节中。 0 表示扩展节点类型,1 表示叶子节点,偶为 0,奇为 1。最终可以得到唯一标识的前缀标识:

  • 0:偶长度的扩展节点
  • 1:奇长度的扩展节点
  • 2:偶长度的叶子节点
  • 3:奇长度的叶子节点

当偶长度时,第一个字节的低四位用0填充,当是奇长度时,则将 key[0] 存放在第一个字节的低四位中,这样 HP 编码结果始终是偶长度。 这里为什么要区分节点 key 长度的奇偶呢?这是因为,半字节 101 在转换为 bytes 格式时都成为<01>,无法区分两者。

例如,上图 “以太坊 MPT 树的哈希计算”中的控制节点1的key 为 [ 7 2 6 f 6 d],因为是偶长度,则 HP[0]= (00000000) 2=0,H[1:]= 解码半字节(key)。 而节点 3 的 key 为 [1 6 e 6 5],为奇长度,则 HP[0]= (0001 0001)2=17。

下面是 HP 编码算法的 Go 语言实现:

// trie/encoding.go:37
func hexToCompact(hex []byte) []byte {
    terminator := byte(0)
    if hasTerm(hex) {
        terminator = 1
        hex = hex[:len(hex)-1]
    }
    buf := make([]byte, len(hex)/2+1)
    buf[0] = terminator << 5 // the flag byte
    if len(hex)&1 == 1 {
        buf[0] |= 1 << 4 // odd flag
        buf[0] |= hex[0] // first nibble is contained in the first byte
        hex = hex[1:]
    }
    decodeNibbles(hex, buf[1:])
    return buf
}
func decodeNibbles(nibbles []byte, bytes []byte) {
    for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 {
        bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1]
    }
}

在 Go 语言中因为叶子节点的末尾字节必然是 16(Hex 编码的终止符),依据此可以区分扩展节点还是叶子节点。

参考资料

  1. https://github.com/ethereum/wiki/wiki/Patricia-Tree
  2. https://ethereum.github.io/yellowpaper/paper.pdf#appendix.D
  3. https://ethereum.github.io/yellowpaper/paper.pdf#appendix.C
  4. https://ethfans.org/toya/articles/588
  5. https://blog.ethereum.org/2015/11/15/merkling-in-ethereum/
  6. https://arxiv.org/pdf/1909.11590.pdf
 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
去中心化交易所(DEX)协议整理 5年以前  |  4378次阅读
详解以太坊默克尔压缩前缀树-MPT 5年以前  |  3136次阅读
以太坊交易回执-Receipt 5年以前  |  2855次阅读
墨客区块链(MOAC BlockChain) 助记词 5年以前  |  2840次阅读
以太坊基础配置 5年以前  |  2766次阅读
 目录