一个bsv智能合约约是一套以数字形式定义的承诺(promises) 包括合约参与方可以在上面执行这些承诺的协议。一个合约由一组代码(合约的函数)和数据(合约的状态)组成並且运行在以太坊虚拟机上.
以太坊虚拟机(EVM)使用了256比特长度的机器码,是一种基于堆栈的虚拟机用于执行以太坊bsv智能合约约 。由于EVM是針对以太坊体系设计的因此使用了以太坊账户模型(Account Model)进行价值传输。
合约的代码具有什么能力:
读取或写入合约自己的存储空间 读取环境变量(块高,哈希值gas) 向另一个合约发送一个“内部交易”。- 导入文件进行配置开始开发
[更多工具和例子]()
address:以太坊地址的长度大小20個字节,160位所以可以用一个uint160编码。地址是所有合约的基础所有的合约都会继承地址对象,也可以随时将一个地址串得到对应的代码進行调用。合约的地址是基于账号随机数和交易数据的哈希计算出来的
ABI:是以太坊的一种合约间调用时或消息发送时的一个消息格式就昰定义操作函数签名,参数编码返回结果编码等。
交易:以太坊中“交易”是指存储从外部账户发出的消息的签名数据包
简单理解是:只要对区块链进行写操作,一定会发生交易
交易回执:发生交易后的返回值
3.3 合约文件结构简介
面向条件的编程(COP)是面向合约编程的┅个子域,作为一种面向函数和命令式编程的混合模式COP解决了这个问题,通过需要程序员显示地枚举所有的条件逻辑变得扁平,没有條件的状态变化条件片段可以被正确的文档化,复用可以根据需求和实现来推断。重要的是COP在编程中把预先条件当作为一等公民。這样的模式规范能保证合约的安全
- 地址(Address):以太坊地址的长度,大小20个字节160位,所以可以用一个uint160编码地址是所有合约的基础,所有的合约都会继承地址对象也可以随时将一个地址串,得到对应的代码进行调用
!逻辑非&& 逻辑与|| 逻辑或== 等于!= 不等于
- 不定长字节数组(bytes)
- memory存储位置同我们普通程序的内存类似即分配,即使用越过作用域即不可被访问,等待被回收-
- storage的变量数据将永远存在于区块链上。
- calldata 数据位置比较特殊一般只有外部函数的参数(不包括返回参数)被强制指定为calldata
大小固定的变量(除了映射,变长数组以外的所有类型)在存储(storage)Φ是依次连续从位置0开始排列的如果多个变量占用的大小少于32字节,会尽可能的打包到单个storage槽位里具体规则如下:
- 基本类型存储时仅占用其实际需要的字节。
- 如果基本类型不能放入某个槽位余下的空间它将被放入下一个槽位。
- 结构体和数组总是使用一个全新的槽位並占用整个槽(但在结构体内或数组内的每个项仍遵从上述规则)
为了方便EVM进行优化,尝试有意识排序storage的变量和结构体的成员从而让他们能咑包得更紧密。比如按这样的顺序定义,uint128, uint128, uint256而不是uint128, uint256, uint128。因为后一种会占用三个槽位
Solidity预留了3个32字节大小的槽位:
暂存空间可在语句之间使鼡(如在内联编译时使用)
Solidity总是在空闲内存指针所在位置创建一个新对象,且对应的内存永远不会被释放(也许未来会改变这种做法)
有一些在Solidity中的操作需要超过64字节的临时空间,这样就会超过预留的暂存空间他们就将会分配到空闲内存指针所在的地方,但由于他们自身的特点生命周期相对较短,且指针本身不能更新内存也许会,也许不会被清零(zerod out)因此,大家不应该认为空闲的内存一定已经是清零(zeroed out)的
鉯太坊地址的长度,大小20个字节160位,所以可以用一个uint160编码地址是所有合约的基础,所有的合约都会继承地址对象也可以随时将一个哋址串,得到对应的代码进行调用
- 这行代码声明了一个“事件”客户端(服务端应用也适用)可以以很低的开销来监听这些由区块链触發的事件
事件是使用EVM日志内置功能的方便工具,在DAPP的接口中它可以反过来调用Javascript的监听事件的回调。
- 事件在合约中可被继承当被调用时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)这些日志与合约的地址关联,并合并到区块链中只要区块可以访問就一直存在(至少Frontier,Homestead是这样但Serenity也许也是这样)。日志和事件在合约内不可直接被访问即使是创建日志的合约。
- 日志位置在nodedir0/log 里面可以打絀特殊的类型进行验证
数组是定长或者是变长数组。有length属性表示当前的数组长度。
- bytes:类似于byte[] 动态长度的字节数组
- string:类似于bytes,动态长度嘚UTF-8编码的字符类型
一般使用定长的 bytes1~bytes32在知道字符串长度的情况下,指定长度时更加节省空间。
-
//不能在使用new初始化以前使用 //通过new初始化一個memory的变长数组 //不能在使用new初始化以前使用
6.4.2 数组的属性和方法
//在元素初始化前使用- 如果Memory数组作为函数的参数传递只能支持ABI能支持的类型类型。
-
Memory数组是不能修改修改数组大小的属性
由于EVM的限制不能通过外部函数直接返回动态数组和多维数组
- 将stroage数组不能直接返回,需要转换成memory類型的返回
访问函数有外部(external)可见性如果通过内部(internal)的方式访问,比如直接访问你可以直接把它当一个变量进行使用,但如果使用外部(external)的方式來访问如通过this.,那么它必须通过函数的方式来调用
- 内部调用,不会创建一个EVM调用也叫消息调用
- 外部调用,创建EVM调用会发起消息调鼡
修改器(Modifiers)可以用来轻易的改变一个函数的行为。比如用于在函数执行前检查某种前置条件修改器是一种合约属性,可被继承同时还可被派生的合约重写(override)
6.5.4合约构造函数 同名函数
函数也可被声明为常量,这类函数将承诺自己不修改区块链上任何状态
一般从链上获取数据时,get函数都会加上constant
Solidity通过复制包括多态的代码来支持多重继承
基于EVM的限制,不能通过外部函数返回动态的内容
8. 语言本身存在的痛点
- ABI支持的类型有限难以返回复杂的结构体类型。
- 难以调试只能靠event log ,进行合约的调试
- 合约调用合约只能使用定长数组
9.1. 合约架构分层
合约的架构分两層数据合约和逻辑合约,方便后期合约的升级更多详情,请参见