📢Web3开发面试题合集(一)
00 分钟
2024-9-19
2024-9-19
type
status
date
summary
tags
category
icon
password
slug

IBuidl | Web3开发面试题合集(一)

1. 私有、内部、公共和外部函数之间的区别?

在Solidity中,函数的可见性(Visibility)定义了谁可以访问该函数。主要有四种可见性修饰符:private(私有)、internal(内部)、public(公共)和external(外部)。它们的区别如下:
  • private(私有)
    • 只能在定义该函数的合约内部调用,不能被外部调用。
    • 继承该合约的子合约无法访问private函数。
  • internal(内部)
    • 可以在定义该函数的合约内部调用,也不能外部调用。
    • 继承该合约的子合约可以访问internal函数。
    • internal是默认的函数可见性修饰符。
  • public(公共)
    • 可以在合约内部、继承合约的子合约中、以及外部(例如通过交易或外部合约调用)访问。
    • 从合约外部调用public函数时,Solidity会生成一个与该public函数相对应的外部接口,使其能够被外部调用。
    • 编译器会自动为public状态变量创建getter函数。
    • external(外部)
      • 只能从合约外部调用。不能从合约的内部调用该函数(但可以使用this.functionName()调用)。
      • public函数更加节省gas,因为参数不需要从内存复制到calldata
    为什么externalpublic函数更加节省gas?
    让我们看一个示例:
    这涉及Solidity中的内存管理和gas优化:
    1. 内存(memory) vs 调用数据(calldata):
        • memory是函数执行期间存储数据的临时区域。
        • calldata是只读的输入数据位置,不会被复制。
    1. public函数的行为:
        • 参数会复制到内存中,因此消耗更多gas。
    1. external函数的行为:
        • 直接从calldata读取数据,避免了复制步骤,节省gas。
    1. Gas节省:
        • 复制大型数组或结构体到内存是昂贵的操作,external函数通过读取calldata节省了gas。
    1. 使用场景:
        • external函数适合处理大型数据输入。

    什么时候使用memory修饰符,什么时候使用calldata修饰符?

    在Solidity中,memorycalldata是两种用于指定数据存储位置的关键字,它们在函数参数和局部变量中的使用有所不同。理解何时使用memorycalldata对优化gas消耗和确保正确的数据处理非常重要。

    memory 修饰符

    • 临时数据存储:memory表示数据只在函数执行期间临时存储。函数执行完毕后,这些数据会被自动销毁。
    • 可读可写:memory中的数据是可变的(即可以修改)。如果你需要在函数中对数据进行修改,通常使用memory
    • 常用于内部处理:当你在函数内部处理数据并且需要修改这些数据(例如复制、排序、变换),你会将数据存储在memory中。

    使用场景

    1. 需要修改参数数据:如果你需要在函数内部修改传入的参数数据,使用memory
    1. 创建 局部变量:当你需要创建一个临时的数组、结构体或其他复杂数据类型用于内部计算时,使用memory

    calldata 修饰符

    • 只读 数据存储:calldata表示数据直接从调用者的输入中读取(即从事务的输入数据中读取),它是只读的,无法修改。
    • 节省gas:因为calldata中的数据不需要在内存中进行复制,且是只读的,所以在处理较大数据结构(如数组)时,使用calldata可以节省gas。
    • 只能用于外部函数的参数:calldata只能用于外部函数(external函数)的参数,因为它直接映射到事务的输入数据。

    使用场景

    1. 外部函数的 只读 参数:如果函数参数只会被读取,而不会被修改,且这个函数是external的,使用calldata
    1. 优化gas消耗:当处理大数据结构时,使用calldata可以避免不必要的内存复制,从而节省gas。

    memory vs calldata 总结

    使用memory
    • 当你需要在函数内部修改传入的数据。
    • 当你需要在内部创建和使用复杂的数据结构(如数组、结构体)时。
    • 当函数是publicinternal,而非external
    使用calldata
    • 当数据不需要被修改,仅用于读取。
    • 当你希望在外部函数(external)中处理大数据结构且需要优化gas消耗时。

    举例对比

    通过合理使用memorycalldata,你可以在优化gas消耗的同时确保函数的正确性和效率。

    总结

    • private:只能在合约内部调用,子合约不能访问。
    • internal:只能在合约内部或继承的子合约中调用。
    • public:可以被任何人、包括合约内外部调用。
    • external:只能从合约外部调用,不能在合约内部直接调用(除非通过 this 关键字)。
     

    2. 智能合约大小大约可以多大?

    在以太坊虚拟机(EVM)中,智能合约的大小限制为24,576字节(24KB),由以太坊协议规定。EIP-170规定了此限制,以保证网络性能与安全。
    这个限制在以太坊改进提案 EIP-170 中进行了规范,这是由于某些极端情况下的安全和资源考虑。实际部署过程中,合约大小应在编写和部署时加以关注,以避免超出这个限制。

    EIP-3860改进提案

    EIP-3860 是一个提议引入字节码长度的 Gas 上限的以太坊改进提案。其主要目标是为创建过长字节码的操作增加额外的 Gas 成本,从而限制超长合约的负面影响。下面是该提案的关键点:

    背景与动机

    在以太坊智能合约中,initcode 是部署合约时发送到 EVM 的字节码。超长的 initcode 会给网络带来负担,尤其是在处理 Gas 费用方面。通过对 initcode 长度引入额外的 Gas 成本,EIP-3860 旨在减少恶意或非故意的超长字节码对网络的潜在影响。

    提案内容

    具体来说,EIP-3860提案要求在部署时根据字节码长度增加 Gas 成本,避免网络因处理过长的字节码而遭受负担。这种机制类似于其他 Gas 成本优化提案,旨在激励开发者编写更简洁的合约代码。

    影响与意义

    EIP-3860 通过引入字节码长度相关的 Gas 成本,鼓励开发者优化合约的字节码,从而减少部署超大合约的频率。这不仅可以缓解网络压力,还可以提高合约执行的效率和安全性。
    虽然该提案不会直接改变合约的大小限制(24 KB),但会影响开发者在编写和部署合约时的成本考量。
     

    3. 在实际生产中,如果想要保证测试网和主网的合约地址一致,应当怎么做?

    方案一:合约地址是由 nonce 和 address 决定的,所以只要保证 nonce 和 address 一样即可。
    方案二:使用 create2, 该操作码背后的整体思想是使结果地址独立于未来事件。无论区块链上发生什么,总是可以将合约部署在预先计算的地址上。
    新地址是以下函数的函数:
    0xFF,一个防止与碰撞的常数CREATE
    发件人自己的地址
    盐(发送者提供的任意值)
    待部署合约的字节码
    CREATE2保证如果使用和提供的sender进行部署,它将存储在.bytecodeCREATE2saltnew_address
    因为bytecode包含在此计算中,所以其他代理可以依赖这样一个事实:如果合约曾经部署到 new_address,那么它将是他们所知道的。这是反事实部署背后的关键概念。

    4. Solidity智能合约的pure与view使用原理及场景

    pure 与 view 原理

    pure:不读取更不修改区块上的变量,使用本机的CPU资源计算我们的函数。所以不消耗任何的资源这是很容易的理解的。
    view: 但是 view 既然要读取区块链上的值,为什么也不用消耗 gas 呢?
    其实很简单,因为作为一个全节点来说,会同步保存所有的信息,保存在本地中。
    那么我们要查看区块链上的资源,同样可以直接在一个全节点之上查询数据即可。
    我不需要全世界的节点都知道。都去同时的处理这笔事务。我也不需要将调用这笔函数的信息记录在区块链上。
    所以 view 仍然不消耗 gas。
    view: 可以自由调用,因为它只是“查看”区块链的状态而不改变它
    pure: 也可以自由调用,既不读取也不写入区块链
    要将固定长度的字节数组转换为动态长度的字节数组,需要首先创建动态数组,并挨个赋值。

    5. 简单说明智能合约的构造函数和初始化函数的特性与区别

    • 构造函数: 在合约部署时调用,仅用于此时初始化状态变量。
    • 初始化函数: 手动调用一次,用于初始化合约。
     
    为了帮助大家顺利转型 Web3,我们决定推出 Web3 开发面试题系列!今天送上第一期,既能让你提前感受面试难度,也能为大家的学习加把劲儿。
    如果觉得有帮助,别忘了转发给有需要的小伙伴哦~
     
    💡
    Let’s buidl
    如果你是数字游民或对Web3感兴趣,欢迎加入我们的Discord社区和关注我们的Twitter。我们不仅探讨技术话题,还涵盖各种Web3相关话题,以及英语学习、数字游民的生活方式、资源和活动。与全球志同道合的朋友一起,探索未来的无限可能!
    期待与你相遇!
     
    上一篇
    IBuidl Web3 Weekly space|普通人如何快速进入Web3的世界?
    下一篇
    PayFi将引领金融革命?盘点5大Web3支付项目

    评论
    Loading...