您好,登录后才能下订单哦!
这篇文章主要介绍“面向老程序员的Solidity知识点有哪些”,在日常操作中,相信很多人在面向老程序员的Solidity知识点有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”面向老程序员的Solidity知识点有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
与Java代码类似,Solidity代码会先被编译成字节码,然后再由EVM负责执行。从逻辑上来讲,可以将以太坊视为一台计算机,其中的每个EVM节点类似在计算机中执行的进程,分布式账本则是这台计算机的存储。
一旦部署成功,其代码会被复制到以太坊上其他节点,并可以通过命令查看其源码。以Truffle开发环境为例:
truffle develop
部署MyCoin合约,deploy
MyCoin.at(地址),从其返回的json对象中的source属性即可看到合约代码。
合约部署之后就无法更新,这就给开发者带来了相当大的挑战:
如何开发出高质量的合约,尽可能的没有Bug?
如何设计可升级的合约?
说到程序执行的代价,一般指的都是花多少内存、存储和CPU时间。但执行以太坊上的代码,除了这些通常意义的代价之外,还需要真金白银。这是因为以太坊上的交易确认都是需要花钱的!它们主要是那些改变以太坊状态的操作,如:
账户转账
部署合约
合约内的写操作
而且,与其他系统不同,这些操作的执行结果并不会立刻生效。它们会以交易的形式提交到交易池中等待矿工确认,这便是交易费的由来。并且,这个价格也不是一个固定值,它随着市场行情的波动上下浮动。如果你的交易长时间没有结果,那么可以看看是否是因为交易费过低。
关于交易费的行情,可以从最新的交易(https://etherscan.io/txs)中了解。
这也给开发者带来了挑战:如何在实现功能的前提下尽可能的降低交易成本?
要在以太坊上进行操作,必需要有以太坊账户。当前有两类账户类型:
外部账户,可简单认为是“人类用户”,有私钥和余额,交易发送前会用私钥先签名。
合约账户,合约部署之后,会随之对应有一个账户,由余额和相应的合约状态数据。它由外部消息来触发执行。触发源来自外部账户或其他合约账户。
这里也带来了一些关于安全性方面的概念转变:
私钥是终极秘密,一定是本地存储,否则都是不安全的。
由于合约是公开的,谁都可以发起执行。如果要实现“只有xxx才能执行本合约”,必需要在合约内部代码中进行控制。
合约类似Java中的类,但与类不同之处在于,它的构造函数只会被调用一次,即部署合约的时候。
合约的状态变量相当于类的实例变量,但同样是持久化的。并且,mapping只能声明成状态变量但可在函数内引用。
变量类型同样也分值类型和引用类型,其中引用类型包括:数组和结构体,后者给自定义类型提供方案。
函数可以返回一个值或多个值,同时可以指定返回的变量。如:
function arithmetic(uint _a, uint _b) public pure returns (uint o_sum, uint o_product) { o_sum = _a + _b; o_product = _a * _b; }
函数修改器(Modifier)类似AOP中的拦截器,提供了修改函数执行流程的机会,一般用来做验证和检查。其中“_”用来将控制流返还给被修改的函数,如下例:
modifier onlySeller() { // Modifier require( msg.sender == seller, "Only seller can call this." ); _;} function abort() public onlySeller { // Modifier usage // ... }
几个重要的修改器:
payable,接收以太的函数必需加上
view或pure,表示函数不会改变以太坊状态
事件提供了让外部应用了解合约状态变化的途径,一般使用流程是:
合约内部发出事件
外部应用利用web3监听事件
可见性:
external,仅适用于函数,表示其可被外部合约或交易调用,但不能被内部调用。
public
函数缺省的可见性,可被内部调用和通过消息调用,
状态变量,EVM会为其自动产生getter
internal,函数和状态变量可被当前合约和其子合约调用
状态变量的缺省可见性
private,函数和状态变量仅被当前合约调用
合约支持多重继承。
EVM提供了4种数据位置用来存放数据:
storage,持久化,存储于整个以太坊
memory,函数的本地内存,非持久化
calldata,函数入参,非持久化
stack,EVM的调用栈
规则:
状态变量:storage
external函数入参:calldata
函数入参:memory
函数局部变量:
引用类型,缺省为storage,但可被覆盖
值类型,memory,不可被覆盖
mapping类型,指向外部的状态变量
状态变量之间赋值,将产生独立副本,即相互更改不受引用。
storage和memory变量之间相互赋值,总产生独立副本。
memory变量之间赋值
值类型,产生独立副本
引用类型,指向同一地址
由于合约执行是有成本的,需要警惕循环语句。
对于多重继承的合约,需要明确指明顺序,如:
contract X {}contract A is X {}contract C is A, X {}
fallback函数没有函数名,无法直接调用,但在两个情况下会被触发:
合约中无任何函数匹配调用者发过来的请求时
合约接收以太时,此时,fallback函数需使用payable
由于其无法被外部调用,EVM限制其只能最多消耗2300的gas,若超过,则fallback函数失败。因此,记得要测试合约的fallback函数是否会超过这个限制。
并且,fallback是安全事故的高发地,需要对其进行必要的安全相关的测试。
接口和抽象合约跟Java中的接口和抽象类差别不大,库(library)是一段可复用的代码,在调用它的合约上下文内执行:
它不能用状态变量
不能继承或被继承
不能接收以太
合约抛出异常之后,状态回滚,当前有3种方式:
require(表达式),若表达式为false,则抛出异常,未使用的gas退回
适合验证函数的入参
assert(表达式),同上,但未使用的gas不会退回,将全部被消耗
适合验证内部状态
revert(),直接抛出异常
鉴于以太坊应用的以下特点,编写solidity代码时需要非常小心:
执行消耗真金白银
合约公开可见,即使是private
合约不可篡改,一旦发布无法变更
常见的编码套路有:
对于支付,优先采用“取款”,而不是“转账”(即send或transfer),避免接收合约恶意fallback函数。
对于支付,采用CDI模式,避免重入问题。即:
检查 -> 更改本合约状态 ->支付。
善用Modifier进行权限控制。
使用mapping类型保存合约数据,甚至为了方便升级,单独分离出两类:
数据合约,仅包含mapping,保留操作mapping的函数,客观上类似数据表。
控制合约,仅包含逻辑控制,通过数据合约的接口操作数据。若逻辑有问题,只需升级本合约即可,数据仍然得以保留。
使用代理合约。
最后,也是最省事的方式:使用成熟类库,如OpenZeppelin。
到此,关于“面向老程序员的Solidity知识点有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。