calldata是交易的数据或外部函数调用的参数所在的位置。它是一个只读的数据位置。你不能写到它。 Calldata 的行为主要类似于内存,是一个可由字节编址的空间。...参考类型 对于数组(固定或动态大小的数组, 如uint256[]), bytes, string, 结构和映射, 你必须明确提供存储值的数据区域....A) 对于参数(=函数定义) B) 对于函数内部的局部变量(=函数主体) C) 返回值总是在内存中(=函数定义)。...对于memory和calldata也是如此。这样的关键字指向 EVM 内存中的某个位置或从交易中进来的输入数据(=calldata)的指针。...对于 memory =总是可以复制内存中的任何数据(无论它来自合约的存储还是 calldata)。
空闲内存指针 作为函数参数的memory引用 在函数内部"内存"(memory) 引用 扩展内存成本 合约调用之间的内存 总结 介绍 在介绍性文章深入 Solidity 数据存储位置[8]中,我把 EVM...相对于交易 = 来自于函数调用,或构造函数 (=合约创建) 短期的 = 不持久的和在外部函数调用之间被删除。 EVM 内存是一个字节寻址的空间。中的所有字节最初都是空的(定义为零)。...以下数据和值默认总是在内存中。 复杂类型的函数参数。 复杂类型的局部变量(在函数体内部)。 从函数返回的值,无论其类型如何(都是通过return操作码完成的)。...任何由函数返回的复合值类型必须指定关键字memory。 通过复杂类型的变量/值,指的是诸如结构体、数组、bytes和strings等变量。 一旦函数调用结束,这些用关键字memory定义的变量将消失。...此外,定义为 "memory"的参数使合约能够接收来自不同来源的调用和参数,包括来自 EOA 和外部合约调用(将有效载荷从 "calldata "加载到 "内存"),但也能够直接从内部函数中组合输入。
newName) public onlyOwner {// 只有合约所有者可以调用该函数 name = newName; } 函数返回值: 可以定义函数的返回类型,并在函数结束时返回相应的值...= "Alice" 结构体作为函数参数和返回值: 可以将结构体作为函数的参数或返回值进行传递。...memory: memory 是一种临时存储位置,用于存储函数执行期间的临时数据。它适用于需要在函数内部进行临时计算或处理大量数据的情况。...可以直接在函数内部使用 storage 类型的变量,无需显式声明。 示例: calldata: calldata 是一种特殊的存储位置,用于存储函数参数和外部函数调用的输入数据。...calldata 中的数据是只读的,不能被修改。此存储位置适用于函数参数传递和与外部合约交互。 在函数参数中,默认情况下,所有的非 mapping 类型参数都被视为 calldata 类型。
内存(memory)位置还包含2种类型的存储数据位置,一种是calldata,一种是栈(stack)。 (1) calldata 这是一块只读的,且不会永久存储的位置,用来存储函数参数。...外部函数的参数(非返回参数)的数据位置被强制指定为 calldata ,效果跟 memory 差不多。...变量默认存储位置: 函数参数(包含返回的参数)默认是memory; 局部变量(local variables)默认是storage; 状态变量(state variables)默认是storage;...计算键的哈希值是一个好的开始,但必须注意确保不同的mappings产生不同的位置。...参考 1) 智能合约语言 Solidity 教程系列4 - 数据存储位置分析 2) 了解以太坊智能合约存储 3) 也来谈一谈以太坊虚拟机EVM的缺陷与不足 - 栈的解释 4) SOLIDITY类型
此过程在智能合约的生命周期内仅执行一次。初始化代码并不会被存储在智能合约中,实际上它执行的返回值也就是字节码才会被存在智能合约中。切记,智能合约一旦被创建,任何人都无法更改其代码。...唯一的区别就是使用内联汇编进行消息调用允许处理返回数据,而如果使用函数只返回1或0来代表调用是否失败。...Calldata calldata是一个只读的字节编址空间,其中保存交易或调用的数据参数。与堆栈不同,要使用calldata数据,你必须准确指出字节偏移量和要读取的字节数。...calldatacopy需要三个参数(t,f,s):它会将位置为f的calldata中的s个字节复制到位置为t的内存中。此外,Solidity语言允许你通过msg.data访问calldata。...对于映射,该位置并未使用,并且对应于键k的值将位于哈希计算keccak256(k,p)产生的位置。哈希计算keccak256(k和p)的参数始终需要填充为32个字节。
这系列文章也会收录在我的个人知识库项目 《区块链入门指南》中,希望在学习过程中不断完善。有兴趣的朋友也可以访问项目仓库参与贡献或提出建议。 本文为系列第一篇,主要涉及 Solidity 基础知识。...智能合约 与 Solidity 语言 智能合约是运行在链上的程序,合约开发者可以通过智能合约实现与链上资产/数据进行交互,用户可以通过自己的链上账户来调用合约,访问资产与数据。...Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言,在 EVM 虚拟机上运行,语法整体类似于 Javascript,是目前最流行的智能合约语言,也是入门区块链与 Web3 所必须掌握的语言...storage,会存储在链上 memory,在内存中,只有方法被调用的时候才存在 calldata,作为调用方法传入参数时存在 而常量是一种不可以改变值的变量,使用常量可以节约 gas 费用,我们可以通过...当一个不接受任何参数也不返回任何参数的函数、当 Ether 被发送至某个合约但 receive() 方法未实现或 msg.data 非空时,会调用 fallback() 方法。
写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 这部分的内容官方英文文档讲的不是很透,因此我在参考Solidity...引用类型是一个复杂类型,占用的空间通常超过256位, 拷贝时开销很大,因此我们需要考虑将它们存储在什么位置,是memory(内存中,数据不是永久存在)还是storage(永久存储在区块链中) 所有的复杂类型如数组...可为memory和storage。 根据上下文的不同,大多数时候数据位置有默认值,也通过指定关键字storage和memory修改它。 函数参数(包含返回的参数)默认是memory。...状态变量:合约内声明的公有变量 还有一个存储位置是:calldata,用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。...function)的参数(不包括返回参数)强制为:calldata 状态变量(State variables)强制为: storage 默认数据位置(Default data location) 函数参数及返回参数
引用类型是一个复杂类型,占用的空间通常超过256位, 拷贝时开销很大,因此我们需要考虑将它们存储在什么位置,是存储在memory(内存,数据不是永久存在)中还是存储在storage(永久存储在区块链)中...根据上下文的不同,大多数时候数据存储的位置有默认值,也可以通过指定关键字storage和memory修改它。 函数参数(包含返回的参数)默认是memory。...除此之外,还有一个存储位置是:calldata,用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。效果与memory差不多。...还有一个存储位置是:calldata,用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。效果与memory差不多。...定义方式为mapping(_KeyType => _KeyValue)。键类型允许除映射、变长数组、合约、枚举、结构体外的几乎所有类型值类型没有任何限制,可以为任何类型包括映射类型。
不要将任何敏感数据存放在合约中,因为合约中的任何数据都可被读取,包括private 定义私有数据。...slotA 表示变长数组声明的位置,用 length 表示变长数组的长度,用 slotV 表示变长数组数据存储的位置,用 value 表示变长数组某个数据的值,用 index 表示 value 对应的索引下标...memory(内存) memory 是一个字节数组,其插槽大小为 256 位(32 个字节)。数据仅在函数执行期间存储,执行完之后,将会被删除。它们不会保存到区块链中。...calldata(调用数据) calldata 是一个不可修改的,非持久性的区域,用于存储函数参数,并且其行为基本上类似于 memory。...调用外部函数的参数需要 calldata,也可用于其他变量。 它避免了复制,并确保了数据不能被修改。 带有 calldata 数据位置的数组和结构体也可以从函数中返回,但是不可以为这种类型赋值。
storage 或 memory 进行修改 函数参数(包括返回的参数)的数据位置默认是 memory, 局部变量的数据位置默认是 storage,状态变量的数据位置强制是 storage 另外还存在第三种数据位置..., calldata ,这是一块只读的,且不会永久存储的位置,用来存储函数参数。...外部函数的参数(非返回参数)的数据位置被强制指定为 calldata ,效果跟 memory 差不多 数据位置总结 强制指定的数据位置 外部函数的参数(不包括返回参数): calldata; • 状态变量...: storage默认数据位置 函数参数(包括返回参数): memory; • 引用类型的局部变量: storage 值类型的局部变量:栈(stack) 特别要求 公开可见(publicly visible...) 回退函数(fallback function)是合约中的特殊函数;没有名字,不能有参数也不能有返回值 如果在一个到合约的调用中,没有其他函数与给定的函数标识符匹配(或没有提供调用数据),那么这个函数
尽量减少链上数据(使用事件、IPFS、无状态合约、merkle 证明)。 最小化链上操作(字符串、返回存储值、循环、本地存储、批处理) 内存位置(calldata、栈、内存、存储)。...无状态合约:如果你只需要将区块链作为一个去中心化的数据库来存储一些 "简单" 的数据,如键/值对或类似的数据,你可以使用无状态合约。思路是部署一个带有定义一些输入参数的函数,但不真正存储任何数据。...你将不需要存储所有交易的哈希值。 尽量减少链上操作 在智能合约上执行的功能,应该只在出于安全、法律或任何其他非常好的理由下才添加。...Calldata :只适用于输入参数且参数是外部函数的引用数据类型(数组,字符串 ...)。...Calldata 参数是只读的,如果你有一些需要传递给函数的引用类型,总是考虑使用 calldata,因为它是最便宜的。 栈:只对方法中定义的值类型数据有效。
译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3] 你可能想知道如何破译和读取 evm 的 calldata,然后试图读取以太坊智能合约的交易 calldata,EVM(和其他...在这篇文章中,我们将深入研究 calldata 的编码顺序,以便你能理解任何经过验证或未经验证的智能合约交易,并理解这些字节。通过这样做,我希望能让你有能力创建自己的原始 calldata。...什么是 Calldata? Calldata 是我们发送给函数的编码参数,在这里是发送给以太坊虚拟机(EVM)上的智能合约。每块 calldata 有 32 个字节长(或 64 个字符)。...我们需要知道参数类型的顺序,并使用一种叫做 "keccak256 "的 Hash 算法,将输入的数据变成一个 32 字节的 hash 值: 在此案例中,要获取函数哈希: function transfer...你可能想知道,calldata 参数究竟是如何被输入到带有签名的函数中的?
在 Solidity 中,有三种数据存储位置:storage、memory 和 calldata。这三者的差异主要在于它们的数据保存位置和存储周期。...3.Calldata: Calldata 用于函数参数,特别是对于 external 函数参数,这类数据只读且在函数调用期间存在。...storage 的状态变量;在函数 f 中,变量 y 在 memory 中;而函数 g 中,参数 x 是 calldata 类型,仅在函数调用期间可用。...理解这三种数据存储位置之间的差异以及它们如何影响合约的成本,能帮助我们更有效地编写和优化智能合约。...如果需要长期存储数据,那么数据应被存储在 storage;否则,如果数据是临时的,它应在 memory 中存储。对于外部函数参数,应优先考虑使用 calldata 来降低 gas 成本。
中心化的注册机制有助于后向兼容性以及更好的功能扩展。一个期望调用ERC777的DApp或智能合约,就可以利用EIP-820返回的ITokenReceipt接口来确定目标合约是否实现了期望的接口。...任何合约都可以定义收到代币时触发的tokensReceived事件,这避免了在ERC20代币 中存在的双重调用问题。...合约和常规地址都可以通过注册一个tokensToSend或tokensReceivedFunction 函数来控制或拒绝发送或接收的代币,避免ERC20代币中存在的代币卡死问题。...如果合约支持切换启用或禁止ERC20的方法,那么每次进行切换时,该代币合约必须通过ERC820注册或解除RC20Token接口的注册。...对于实现ERC20的新合约而言,唯一的区别在于ERC777TokensSender和ERC777TokensRecipient通过ERC820的注册必须早于ERC20的注册。
在上一篇文章[4],中,我们了解了数据位置的工作方式以及何时可以使用以下三个位置:memory,storage和calldata。 在本文中,我们将继续学习 Solidity 中的变量。...映射声明如下: mapping( KeyType => ValueType) VariableName KeyType可以是任何内置值类型(我们在第一篇[10]介绍过)、字节或字符串中看到的值、也可以是任何合约或枚举类型...ValueType可以是任何类型,包括映射,数组和结构体。 这里要提到的一件事是,映射变量唯一允许的数据位置是storage,它只能声明为状态变量、存储指针或库函数的参数。...对于constant,该值必须在编译时确定,而对于immutable,则是在构造时赋值。 编译器不会为这些变量保留一个存储槽,而是在每次出现时会由相应的值替换。...对于数组,它分配长度为零的动态数组或长度相同的静态数组,并将所有元素设置为其初始值。 delete a[x]删除数组索引x处的项目,并保持所有其他元素和数组长度不变。这尤其意味着它在数组中留有间隙。
这个构造函数是可支付的,这意味着你可以在部署合约时向它发送Ether。构造函数将合约的创建者设置为所有者。 3.getBalance:这个函数返回合约所有者的余额。...这个函数在合约收到普通Ether转账时被调用,它不能有参数,也不能返回任何值。 receive函数必须被声明为external payable,并且一个合约只能有一个receive函数。...注意,receive函数被声明为external payable,并且没有任何参数或返回值。...此外,fallback函数可以接受一个bytes calldata参数,并且可以返回bytes memory: // SPDX-License-Identifier: MIT pragma solidity...例如,你可能希望在没有任何数据的情况下(即msg.data为空)执行一种操作(通过receive()函数),而在有数据的情况下执行另一种操作(通过fallback()函数)。
为了充分了解这意味着什么,以及这些字节的作用,我们必须首先建立你对管理合约内存(memory)的数据结构的认知。...内存(memory)的数据结构 合约内存是一个简单的字节数组,数据可以以 32 字节(256 位)或 1 字节(8 位)为单位存储,以 32 字节(256 位)为单位读取。...我们获得一个返回值,并被压入了栈区(stack)。这意味着我们可以从非 32 字节对齐的内存位置读取数据。记住内存是一个字节数组,这意味着我们可以从任何内存位置开始读(和写)。...Free Memory Pointer(自由内存指针) Free Memory Pointer 只是一个指向自由内存开始位置的指针。它确保智能合约知道已写入和未写入的内存位置。...calldataOffset 是我们 calldata 的实际大小,因为我们不想复制任何 calldata,我们想用零值初始化内存。最后,大小是 0xa0 或 160 字节,因为这是该变量的大小。
智能合约设计模式是一种在区块链领域中用于编写智能合约的经验总结和最佳实践。类似于软件工程中的设计模式,智能合约设计模式提供了一套可重用的解决方案,用于解决智能合约开发中常见的问题和挑战。...智能合约一旦部署,就无法对其业务逻辑进行任何更新。这引发了一个明显的问题。 我们如何升级智能合约? 一开始,这个问题通过“合约迁移”来解决。...有时,控制器合约可能会存储某个特定数据合约的地址或命名空间(通过命名空间在运行时获取合约地址)。...对于其他任何人,所有调用都将通过回退函数委托给“实现”,即使存在匹配的函数签名。 这消除了歧义,管理员可以与“代理”函数交互,非管理员只能与“实现”函数交互。...委托调用将控制权传递给实现合约,并返回结果。 委托调用的返回数据被复制到内存中,并作为返回结果返回给用户。 管理员访问 管理员流程引入了一个新的合约“代理管理员”和库 ERC1967Utils。
回顾一下 solidity 中数据位置,即说明数据存储在哪里,solidity 有 3 个位置: 1.memory :(内存) 即数据在内存中,因此数据仅在其生命周期内(函数调用期间)有效。...2.storage :(链上存储空间),就是状态变量保存的位置,只要合约存在就一直存储.3.calldata :(调用数据),一个特殊只读数据位置,用来保存函数调用参数(之前仅针对外部函数)。...请注意,由于EVM不允许修改 calldata,因此无法在 calldata 变量中创建新值或将某些内容复制到 calldata变量。...= _newOwners[i]); } } 使用 calldata 变量的好处是,它不用将 calldata 数据的副本保存到内存中,并确保不会修改数组或结构(calldata 位置是只读的),因此...,如果可以的话,请尽量使用 calldata 作为数据位置 函数的返回值中其实也可以使用 calldata 数据位置,但是无法给其分配空间。
assert 函数只能用于测试内部错误,并检查非变量。 require 函数用于确认条件有效性,例如输入变量,或合约状态变量是否满足条件,或验证外部合约调用返回的值。...可见性标识符的定义位置,对于状态变量来说是在类型后面,对于函数是在参数列表和返回关键字中间。...Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。 你可以把它想象成存储在你电脑的硬盘或是RAM中数据的关系。...如果构造函数参数是常量并且定义或描述了合约的行为,使用第一种方法比较方便。 如果基类构造函数的参数依赖于派生合约,那么必须使用第二种方法。...(uint); } 请注意,这个过程虽然看起来像在定义一个合约,但其实内里不同: 首先,只声明了要与之交互的函数 —— 在本例中为 getNum —— 在其中没有使用到任何其他的函数或状态变量。
领取专属 10元无门槛券
手把手带您无忧上云