前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >EVM 源码解析

EVM 源码解析

原创
作者头像
谛听
修改于 2023-02-09 02:33:45
修改于 2023-02-09 02:33:45
1.3K00
代码可运行
举报
文章被收录于专栏:随意记录随意记录
运行总次数:0
代码可运行

1 EVM

以太坊虚拟机 (Ethereum Virtual Machine, EVM) 负责执行交易和更新区块链状态。

EVM 是一个状态执行的机器,输入是 solidity 编译后的二进制指令和节点的状态数据,输出是节点状态的改变。

像 VirtualBox 或 QEMU 是计算机的虚拟,KVM 是整个操作系统实例的虚拟,他们分别提供了硬件、系统调用和其它内核功能的软件抽象。EVM 则只是一个计算引擎,提供了计算和存储的抽象。EVM 没有调度能力,因为执行顺序是外部组织的。以太坊客户端通过验证的区块交易来确定哪些智能合约需要执行以及执行顺序。从这个意义上讲,以太坊世界计算机是单线程的,就像 JavaScript 一样。EVM 也没有任何“系统接口”处理或“硬件支持”——没有与之交互的物理机器。

EVM 可以访问账户信息(比如地址和余额)和区块链信息(比如 block number 和 gas 费用)。

EVM 的位置:

EVM 位置
EVM 位置

EVM 架构:

EVM 架构
EVM 架构

EVM 由程序计数器 (Program Counter)、堆栈 (Stack)、内存 (Memory) 和外部存储(Storage)组成。

EVM 存储:

EVM 存储
EVM 存储

EVM 中数据可以在三个地方进行存储,分别是栈,临时存储,永久存储。

  • stack,后进先出结构,256 bits * 1024。因为栈的限制,因此栈上的临时变量的使用会受限制。
  • memory,一个可无限扩展的字节数组。临时内存存储在每个 VM 实例中,并在合约执行完后消失。
  • storage,k/v 结构,存储合约状态。不像 stack 和 memroy,计算结束后会被重置,永久内存存储在区块链的状态层

EVM 运行:

EVM 运行
EVM 运行

当 EVM 运行时,它的状态可被定义为 (block_state, transaction, message, code, memory, stack, pc, gas),block_state 包含所有帐户的全局状态,包括余额和存储。每一轮执行开始时,通过 code 的第 pc 个字节获取当前指令,每条指令都有自己的定义,并且影响着状态。例如,ADD 从栈中弹出两项并将它们的总和压栈,将 gas 减 1 并将 pc 加 1。SSTORE 将栈中的前两项压栈,并将第二项按照第一项的索引插入合约存储中。

code 是 solidity 编译后的二进制指令/字节码,EVM 会将 code 分解为 Opcode。理论上共有 256 个长度为 1 字节的 Opcode,但 EVM 只使用了 140 种。code 示例如下:

代码语言:json
AI代码解释
复制
60003560e01c80632e64cec11461003b5780636057361d1461005957

上面示例中的每个字节都指向不同的 Opcode。例如,第一字节(例如 60)是 PUSH1 操作码,下一字节(例如 00)是正被 push 的数据,第三字节(60)是 PUSH2 操作码,而下一字节是其输入(例如 e0)。

启动的每个 EVM 实例都是为了运行一段字节码。因此,字节码就像是 EVM 实例的 ROM,是不能修改的。

一个合约可以调用另一个合约,每次调用都会导致一个新的 EVM 实例化,如下图所示。

合约调用
合约调用

Gas:

gas
gas

每次执行指令时,内部计数器会记录需要向用户收取的佣金。当用户发起交易时,钱包中需要留有少量资金来支付这些佣金。

gas 有两个功能:

  • 经济激励。确保为矿工预付报酬,即使执行失败。
  • 避免网络攻击。确保代码执行的时间不能超过预付的时间。

2 SputnikVM

源码:SputnikVM

2.1 特性

  • 独立 —— 可以作为独立进程启动,也可以集成到其他应用程序中
  • 普适 —— 支持不同的以太坊区块链,如 ETC,ETH 或私有链
  • 无状态 —— 虚拟机本身不保存任何状态,只是将其连接到外部状态储存的执行环境中
  • 高效 —— 运行的高效性是该项目的设计初衷
  • 兼容物联网 —— 可以很方便地在嵌入式硬件设备中运行和使用

2.2 代码结构

  • src 供外部使用的库,包括
    • backend,存储 VM 状态信息(Storage),并暴露给 runtime;获取 block 相关信息。
    • executor,将 gasometer 和 core 连在一起,并处理 stack。
  • core EVM 的核心,定义了基本的执行规则,如 Machine,Memory,Opcode,Stack 等。
  • gasometer 计算 gas。
  • runtime 包含 Machine,支持返回数据和上下文。 与 block,transaction 和 storage 交互。

2.3 代码阅读

benches/loop.rs

SputnikVM 组成:

SputnikVM 组成
SputnikVM 组成

2.3.1 创建 EVM

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let backend = MemoryBackend::new(&vicinity, state);

let metadata = StackSubstateMetadata::new(u64::MAX, &config);
let state = MemoryStackState::new(metadata, &backend);

let precompiles = BTreeMap::new();
let mut executor = StackExecutor::new_with_precompiles(state, &config, &precompiles);
  1. 创建 Backend。
    1. 传入 vicinity,是为了 mock block 信息,生产环境中可以替换为 block header。
    2. 传入 state,是为了保存 VM 状态信息(Storage),生产环境中可以替换为 RocksDB。
  2. 创建 StackSubstateMetadata,会默认创建一个 gasometer 以跟踪 gas 用量。
  3. 创建 StackState,包含 Backend 和 MemoryStackSubstate。
    1. 参数 StackSubstateMetadata 用来创建 MemoryStackSubstate。
    2. 子状态:交易的执行过程中会累积产生一些特定的信息,我们称为交易子状态,包括
      1. 自毁集合,一组应该在交易完成后被删除的账户。
      2. 交易接触过的账户集合,其中的空账户可以在交易结束时删除。
      3. 应该返还的余额,当使用 SSTORE 指令将非 0 的合约 storage 重置为 0 时,该余额会增加。
      4. 日志,针对 VM 代码执行的归档化、可索引的“检查点”,允许以太坊外部的旁观者简单地跟踪合约调用。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pub struct MemoryStackSubstate<'config> {
	metadata: StackSubstateMetadata<'config>,
	parent: Option<Box<MemoryStackSubstate<'config>>>,
  storages: BTreeMap<(H160, H256), H256>,
	logs: Vec<Log>,  // 日志
	accounts: BTreeMap<H160, MemoryStackAccount>,  // 交易所接触过的账户集合
	deletes: BTreeSet<H160>,  // 自毁集合
}
  1. 创建 StackExecutor,包含 StackState 和 precompiles 等。 precompiles 是已编译的智能合约,提供了通用功能,使得以太坊节点高效运行。

2.3.2 执行 CALL 指令

通过给定的 caller,target address,value,data 和 gas limit 执行 CALL 指令。最后一个参数 access_list 是 Ethereum Berlin hard fork 后引入的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let (exit_reason, data) = executor.transact_call(
		H160::from_str("0xf000000000000000000000000000000000000000").unwrap(),
		H160::from_str("0x1000000000000000000000000000000000000000").unwrap(),
		U256::zero(),
		hex::decode("0f14a4060000000000000000000000000000000000000000000000000000000000b71b00")
			.unwrap(),
		u64::MAX,
		Vec::new(),
	);
  1. gasometer 根据 tx.data 和 accest list 计算并记录实际需要消耗的 gas,如果预付的 gas 不够会异常。
  2. caller 所在账户的 nonce 加 1。
  3. 加载 code:查看 accounts 中包含了 target address 的账户,如果包含,则返回该账户的 code;否则,从 backend 中根据 target address 获取账户,进而得到 code。
  4. 进入子状态:根据当前 executor 创建一个拥有子状态的 executor,接下来的操作在子状态 executor 上进行。
  5. 将 target address 所属的 account 添加到交易接触过的账户集合 accounts 中,并标记 reset 为 false。
  6. transfer:如果 caller 账户的余额小于 value,则异常。caller 的余额 -= value,target address 的余额 += value。
  7. 如果 target address 是 precompile 的,则执行 precompile 并记录消耗的 gas,退出子状态,结束;否则,继续下一步。
  8. 根据 code,data 等创建 Runtime,Runtime 会创建 Machine。
  9. 创建调用栈,将 Runtime 压栈。
  10. 循环执行,直到调用栈为空。
    1. 查看当前栈顶的 Runtime,如果类型为 Call,则执行如下步骤。
    2. 检查 gas 是否够。
    3. 循环运行 Machine,直到 code 中的指令都执行完:根据 pc 计数器从 code 中获取当前指令,解释为 Opcode 并执行,执行后更新 pc 计数器。
    4. 如果 Machine 运行正常退出,则执行如下步骤。
    5. 从 runtime.machine.memory 中获取 Machine 执行结果的返回值 return data。
    6. 退出子状态:将子状态更新到当前 executor,如 gas,logs,accounts,deletes 等,从内存中删除 reset 为 true 的 account。
    7. 将当前 Runtime 弹出调用栈。
    8. 从调用栈中获取下一个 Runtime,runtime.return_data_buffer 指向 return data。如果 Runtime 的类型是 Call,将 return data 拷贝到 runtime.machine.memory 中,拷贝成功则在 runtime.machine.stack 中压入 1,否则压入 0。

3 REVM

源码:REVM

3.1 特性

  • EVM 兼容性和稳定性 —— 在区块链行业,稳定性是任何系统最需要的属性。
  • 速度 —— 是最重要的事情之一,大多数决策都是为了补充这一点。
  • 简单 —— 简化内部结构,使其易于理解和扩展,并且接口易于使用或集成到其他项目中。
  • 接口 —— 以便用作 wasm-lib,并在需要时与 JavaScript 和 cpp 绑定集成。

3.2 代码结构

  • crates
    • revm -> EVM 主库
    • revm-primitives -> 数据结构定义,如 Bytecode,Account,DB,Storage,Log,Env 等
    • revm-interpreter -> 指令循环执行
    • revm-precompile -> EVM 预编译合约
  • bins:
    • revme:CLI,用于运行状态测试
    • revm-test:主要用于检查性能

3.3 代码阅读

bins/revm-test/src/bin/snailtracer.rs

REVM 组成:

REVM 组成
REVM 组成

.3.1 创建 EVM

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let mut evm = revm::new();

// BenchmarkDB is dummy state that implements Database trait.
let bytecode = to_analysed::<BerlinSpec>(Bytecode::new_raw(contract_data));
evm.database(BenchmarkDB::new_bytecode(bytecode.clone()));

3.3.2 执行 CALL 指令

EVM 输入:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// execution globals block hash/gas_limit/coinbase/timestamp..
evm.env.tx.caller = "0x1000000000000000000000000000000000000000"
    .parse()
    .unwrap();
evm.env.tx.transact_to = TransactTo::Call(
    "0x0000000000000000000000000000000000000000"
        .parse()
        .unwrap(),
);
evm.env.tx.data = Bytes::from(hex::decode("30627b7c").unwrap());

EVM 运行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
evm.transact().unwrap();
  1. 创建 EvmImpl。
  2. 将 caller 账户从 DB 中加载到内存 state 中。
  3. caller 账户的余额减去 tx.gas_limit * tx.gas_price,余额不足则报错。
  4. 创建 Gas,根据 tx.data 和 access list 计算并记录初始 gas 消耗。
  5. caller 账户的 nonce 加一。
  6. 加载 code:根据 target address 从 DB 中加载 account 到内存 state 中,根据 account 的 code hash 从 DB 中加载 code,并存放到 account.code 中。
  7. 进入子程序:调用栈深度 depth 加 1。如果 depth 超限则报错。
  8. 将 target address 账户标记为 touched。对于较新的硬分叉,这意味着它可以从 state 中删除。
  9. transfer:caller 的余额 -= value,target address 的余额 += value。caller 和 target address 账户均标记为不被删除。
  10. 如果 target address 是 precompile 的,则执行 precompile 并记录消耗的 gas,调用栈深度 depth 减 1,结束;否则,继续下一步。
  11. 根据 code 和 input 等创建 Interpreter。
  12. 检查 gas 是否够。
  13. 循环运行 Interpreter,直到 code 中的指令都执行完:根据 pc 计数器从 code 中获取当前指令,解释为 Opcode 并执行,执行后更新 pc 计数器。
  14. 退出子程序:从内存中删除被标记为 touched 的 account。调用栈深度 depth 减 1。返回消耗的 gas 和计算结果。
  15. 更新并返回当前程序的 gas 和 state。

4 SputnikVM vs REVM

  • 代码结构 相近之处:
    • SputnikVM / src vs REVM / revm,都是供外部使用的库。
    • SputnikVM / core vs REVM / primitives,都会定义核心数据结构。
    • SputnikVM / runtime vs REVM / interpreter,都定义了指令执行。

    不同之处:

    • SputnikVM::PrecompileSet 定义在 src/executor/stack/executor.rs 中;REVM::Precompiles 定义在 precompiles 中,是单独的目录,并提供了一些 precompile 的实现。
    • SputnikVM::Gasometer 定义在 gasometer 中,是单独的目录;REVM::Gas 定义在 interpreter/src/gas.rs 中,被认为是 Interpreter 的一部分。
  • 数据结构 两者有比较相近的数据结构,如:
    • SputnikVM::Machine vs REVM::Interpreter,都用来执行 code。不过 REVM::Interpreter 包含了 gas 计费功能,而在 SputnikVM 中,该部分功能移到了 Machine 外部。
    • SputnikVM::Backend vs REVM::DB,都用于持久化区块链状态。不过 SputnikVM::Backend 中还包含了 REVM::Env 功能。
    • SputnikVM::MemoryStackState vs REVM::JournaledState,都用来维护交易执行过程中的一些状态。不过 SputnikVM::MemoryStackState 还会维护 gas 状态。
  • EVM 创建 REVM 更简单。
  • CALL 指令运行 两者的 CALL 指令运行逻辑基本一致。不过 SputnikVM 会显式维护一个调用栈,而 REVM 采用递归方式。
  • 兼容性 REVM 兼容了更多的 hard fork 情况。
    • REVM — Frontier,Homestead,Tangerine,Spurious,Byzantium,Constantinople,Petersburg,Istanbul,MuirGlacier,Berlin,London,Merge,MergeEOF
    • SputnikVM — Frontier,Istanbul,London,Merge
  • GitHub 上所宣传的优势 共同的优势:高效,理论上当 call 层级较多时,SputnikVM 会更高效一些。 各自的优势:
    • SputnikVM
      • 普适 —— 支持不同的以太坊区块链,如 ETC,ETH 或私有链
      • 兼容物联网 —— 可以很方便地在嵌入式硬件设备中运行和使用
    • REVM
      • 简单 —— 简化内部结构,使其易于理解和扩展,并且接口易于使用或集成到其他项目中。
      • 接口 —— 以便用作 wasm-lib,并在需要时与 JavaScript 和 cpp 绑定集成。

    本人不确定 REVM 是否支持不同的以太坊区块链,是否兼容物联网;不确定 SputnikVM 是否可以用作 wasm-lib。 两者的逻辑相近,个人感觉 REVM 的结构会简单一些。

  • GitHub 指标 SputnikVM 更优。

SputnikVM

REVM

star

837

546

used by

5.1k

219

first release

参考

Ethereum EVM illustrated

以太坊虚拟机 (EVM)

What is the Ethereum Virtual Machine (EVM)?

The Ethereum Virtual Machine

The Ethereum Virtual Machine (EVM) - What Is It and How to Make Business on It?

Ethereum Whitepaper

Ethereum Yellow Paper

SputnikVM

REVM

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
WDC2023 — Web 开发者划重点
即 Google I/O 2023 之后,又迎来了 Apple 举办的当世最令人瞩目的另一大科技大会:WDC2023。这两场大会无疑都会为大家带来近一年内最热门最前沿的技术,而作为 Web 开发者我们也应该紧跟时代的潮流,及时了解技术的进步,从这些大会上我们也能学习到很多有用的内容。
ConardLi
2023/08/23
4400
WDC2023 — Web 开发者划重点
小明带你看WWDC 2017(day4实况)
作者介绍: 黄明,WWDC 2017大会的小时光茶社特派员 ,腾讯SNG增值产品部内容中心iOS组leader,主要负责手Q个性化业务、手Q WebView等项目。作为终端开发也喜欢学习些图像图形方向的知识,同好者可以技术交流。生活中,休闲比较喜欢看书,娱乐比较喜欢电竞。 今天是WWDC的倒数第二天,感兴趣的session越来越少,跟大家分享分享听了这几个。 1. Core ML in depth Core ML in depth,再次跟我们解释了怎么使用Core ML,着重点在于Core ML To
小时光
2018/01/29
8270
小明带你看WWDC 2017(day4实况)
iOS 创建 Universal Links【修订】
When you support universal links, iOS users can tap a link to your website and get seamlessly redirected to your installed app without going through Safari. If your app isn’t installed, tapping a link to your website opens your website in Safari.
公众号iOS逆向
2021/08/25
9390
iOS 创建 Universal Links【修订】
WKWebView详解
WKWebView主要涉及到以下类或协议,各部分可能互相依赖,文章按照apple文档的划分对每一个模块进行了详细的解释。
殷源
2018/01/31
20.9K9
WWDC 2022:哪些是前端开发者要关注的信息?
苹果全球开发者大会(Apple Worldwide Developers Conference,缩写:WWDC)是苹果公司每年定期举办的信息技术交流活动,活动旨在向全球的软件设计师展示苹果公司最新的软件及技术,通常用于展示 macOS、iOS、iPadOS、watchOS 和 tvOS 系列以及其他苹果公司的软件和技术。
ConardLi
2023/01/09
1.8K0
WWDC 2022:哪些是前端开发者要关注的信息?
小明带你看WWDC 2017(day3实况)
作者介绍: 黄明,WWDC 2017大会的小时光茶社特派员 ,腾讯SNG增值产品部内容中心iOS组leader,主要负责手Q个性化业务、手Q WebView等项目。作为终端开发也喜欢学习些图像图形方向的知识,同好者可以技术交流。生活中,休闲比较喜欢看书,娱乐比较喜欢电竞。 今天内容依然是Machine Learning(机器学习),让我们大家持续兴奋。 1. NLP(Nature Language Processing) 还在为终端分词而苦恼吗?没有好的分词算法?分词词库太大?今天参加了我昨日提到的N
小时光
2018/01/29
1.5K0
小明带你看WWDC 2017(day3实况)
WKWebView 那些坑
QQ空间开发团队
2017/08/15
17.6K2
趣谈 iOS Universal Link
说起 Universal Link(通用链接),对于有过 iOS 开发的同学,一定有用上过。目前在申请微信分享或登陆时,需要配置 Universal Link 链接。对于 Universal Link,大家应该都了解:
37手游iOS技术运营团队
2021/12/13
2.6K0
趣谈 iOS Universal Link
下一代Web开发技术-Progressive Web App介绍
PC和Mobile开发技术演进 PC方向,从客户端到富客户端,到现在广泛使用的Web。 移动方向,目前主要还是原生应用和Mobile Web,PWA相关技术是未来发展方向。 PWA的概念 Progressive Web App (中文翻译为:渐进式Web应用)带来的体验将网络应用的优点与原生应用的优点相结合。用户在浏览器中第一次访问时就能体会到它们的好处,因为不需要进行任何安装。在用户随着时间的推移增进与应用的关系后,其功能会变得越来越强大。它即使在不可靠网络上也能快速加载、能够发送相关推送通知、具
企鹅号小编
2018/01/30
1.5K0
下一代Web开发技术-Progressive Web App介绍
关于 iOS 10 中 ATS 的问题
WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推进网络通讯安全的一个重要方式。在 iOS 9 和 OS X 10.11 中,默认情况下非 HTTPS 的网络访问是被禁止的。当然,因为这样的推进影响面非常广,作为缓冲,我们可以在 Info.plist 中添加NSAppTransportSecurity字典并且将NSAllowsArbitraryLoads设置为YES来禁用 ATS。相信大家都已经对这个非常熟悉了,因为我自己也维护了一些网络相关的框架,所以我还自己准备了一个小脚本来快速关闭 ATS。
freesan44
2018/09/05
2.3K0
WWDC 2017前瞻:硬件细节已遭曝光,但苹果在软件方面的布局却始终慎重
北京时间6月6日凌晨1时,一年一度的2017苹果全球开发者大会(WWDC 2017)在美国加州圣何塞市的McEnery会议中心举行。按照惯例,每年6月举行的WWDC侧重于iOS及macOS等系统方面的
VRPinea
2018/05/15
1.3K0
Hybrid App 应用 开发中 9 个必备知识点复习(WebView / 调试 等)
前言 我们大前端团队内部 📖每周一练 的知识复习计划继续加油,本篇文章是 《Hybrid APP 混合应用专题》 主题的第二期和第三期的合集。 这一期共整理了 10 个问题,和相应的参考答案,文字和图片较多,建议大家可以收藏,根据文章目录来阅读。 之前分享的每周内容,我都整理到掘金收藏集 📔《EFT每周一练》 上啦,欢迎点赞收藏咯💕💕。 内容回顾: 《EFT 每周分享 —— Hybrid App 应用开发中 5 个必备知识点复习》 《EFT 每周分享 —— HTTP 的15个常
pingan8787
2019/09/05
3.2K0
Hybrid App 应用 开发中 9 个必备知识点复习(WebView / 调试 等)
iOS防止在WKWebView中打开Universal Link
在wap中唤起app应用最最广泛的方式并不是Universal Link,而是直接Schema跳转
公众号iOS逆向
2021/08/25
3.2K0
iOS防止在WKWebView中打开Universal Link
苹果拒绝支持PWA的行为对Web贻害无穷!
渐进式Web应用(Progressive Web Applications,简称 PWAs)是迄今为止在Web开发中最令人兴奋的创新技术之一。PWA 使你可以用 JavaScript 来创建一个“Service Worker”,它为你提供与原生应用相关联的各种功能,例如推送通知,离线支持和应用的加载屏幕 —— 这一切可都是基于Web的!这真是极好的。
疯狂的技术宅
2019/03/28
2K0
苹果拒绝支持PWA的行为对Web贻害无穷!
移动web开发需要注意的二十点
(现在大部分移动浏览器包括wp都支持viewport的width选项),这些meta标签在开发webapp时起到非常重要的作用,可以给用户提供更好的体验
疯狂的技术宅
2019/03/27
2K0
备受乔布斯推崇的 PWA,为什么还没有杀死原生应用?
作者丨Kevin Basset 译者丨明知山 策划丨褚杏娟 PWA (Progressive Web App)的想法不是由 Google 或 Apple 提出的,而是 Steve Jobs 在 2007 年 iPhone 推出期间首次将这一概念展示在了世界面前。当时,外部应用程序似乎可以帮助提高该设备的受欢迎程度,Jobs 希望开发人员使用标准 Web 技术来构建应用程序。 你可以编写令人惊叹的 Web 2.0 和 Ajax 应用程序,它们的外观和行为与 iPhone 上的应用程序一模一样,而且这些
深度学习与Python
2023/03/29
1.5K0
备受乔布斯推崇的 PWA,为什么还没有杀死原生应用?
移动端web开发入门笔记
本文介绍了移动端网页开发的一些基础概念,包括HTML、CSS、JavaScript,以及用于移动开发的响应式布局和自适应图片等。同时,文章还探讨了如何通过meta标签和viewport来优化移动端网页的展示效果。最后,还介绍了一些移动端网页开发中常见的问题和解决方法。
IMWeb前端团队
2017/12/29
1.9K0
移动端web开发入门笔记
移动端web开发笔记
这是一个最好的时代,因为我们站在潮流中;但也是一个最坏的时代,因为我们站在潮头上。 META相关
李维亮
2021/07/09
3.8K0
移动端web开发笔记
WWDC22 - Apple 隐私技术探索
一直以来,苹果对隐私保护都非常严格,虽然每年新 iPhone 发布都提前被暴光的差不多了,但从 2018 年 Facebook 隐私门事件开始,不管国内还是海外,行业巨头还是个人用户,大家对于隐私的关注都达到了新的高度。正如乔布斯说,开放和安全是截然相反的事情,但这件不容易的事,总需要有人做。从 WWDC20 开始,对用户隐私的保护,又达到了史前的疯狂程度,如推出 ATT(App Tracking Transparency),成为广告行业的敌人,更不要说平时对权限的严控,所以,本文带大家一起回顾苹果关于隐私的升级变化。
37手游iOS技术运营团队
2022/07/11
1.2K0
WWDC22 - Apple 隐私技术探索
Hybrid App 应用开发中 9 个必备知识点复习
前言 我们大前端团队内部 ?每周一练 的知识复习计划继续加油,本篇文章是 《Hybrid APP 混合应用专题》 主题的第二期和第三期的合集。 这一期共整理了 10 个问题,和相应的参考答案,文字和
ConardLi
2019/07/17
2.4K0
Hybrid App 应用开发中 9 个必备知识点复习
相关推荐
WDC2023 — Web 开发者划重点
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档