Browser-solidity :数组增删改查的合约+Token代币合约+Token基于账户的代币合约
我们依然打开Browser-solidity的地址: https://ethereum.github.io/browser-solidity
一个简单的实现对数组增删改查的智能合约
pragma solidity 0.4.9;/*数组类型Demo*/contract DemoTypes303 { /*String数组例子*/ string[] strArr; function add(string str){ strArr.push(str); }
function getStrAt(uint n) constant returns (string s){ string tmp = strArr[n]; return tmp; }
function updateStrAt(uint n, string str) { strArr[n] = str; }
function deleteStrAt(uint index) { uint len = strArr.length; if (index >= len) return; for (uint i = index; i<len-1; i++) { strArr[i] = strArr[i+1]; }
delete strArr[len-1]; strArr.length--; }}
代码分析
-
string[] strArr;
定义了一个字符串的数组变量strArr, 且该变量没有public因此不可见 -
strArr.push(str);
其中的push是数组类型的两个member之一,另一个是length. 这里的push就是给该数组增加一个元素。//这里实现了对数组的新增功能function add(string str){ strArr.push(str);}
-
getStrAt(uint n)
是一个简单的读取字符串的函数,//这里实现对数组的读取功能 -
updateStrAt(uint n, string str)
// 实现对数组的更新功能 -
deleteStrAt(uint index)
这个值得一说,因为solidity默认的数组类型中没有删除功能,因此此处自己写了一个删除代码,核心方法就是保证删除某项后,后面的元素依次向前,同时删除数据,同时保证数组的member length正确。
Browser solidity 部署和调用
将上面的代码复制黏贴到Browser-solidity上面,可以看到编译成功,并生成了可部署的web3 deploy代码。 这里我们在内存中试试看该智能合约的4个基本方法 增删改查1. add function
-
输入
hello 01
, 然后点击add按钮,我们可以看到在经过一部分gas的消耗后,该数据被执行成功! - PS:需要注意的是这里的getStrAt和add,update,delete等方法颜色不同,按上方的分类,一个是transaction,一个则是call,因此在geth上的调用方法也是不同的。
2. getStrAt function
既然已经增加了一个元素,我们就可以查看数组
strArr
的数值了,根据数组常识,我们只增加了一个元素,因此
getStrAt[0]
应该为
hello 01
. 而
getStrAt[1]
则应该为错误。
实际结果如下:getStrAt[0]
getStrAt[1]:
3. updateStrAt functoin
4. deleteStrAt function
要测试这个方法,稍微麻烦点,最好是- step 1需要先add(“hello 01”), add(“hello 02”),add(“hello 03”)
- step 2然后调用deleteStrAt(0);
- step 3 检查是否第一项被删除,而getStrAt(0)应该等于”hello 02″, getStrAt(1)应该等于”hello 03″
- 然后重复step1-3,作用于deleteStrAt(1),删除中间项目,或者deleteStrAt(2)删除最后一项,还有deleteStrAt(3)/deleteStrAt(100)/deleteStrAt(-100) 等检查是否做了边界检查。
作为礼物,这里有另外的几个简单的智能合约,有兴趣的同学都可以多用browser-solidity来尝试
pragma solidity ^0.4.4;
contract DemoTypes { /*uint public resultOfF;*/ event LogUint(uint value); event LogInt (int value);
function f(uint a) returns (uint b) { uint result = a * 8; /*resultOfF = result; //debug used only;*/ LogUint(result); return result; }
/*输入长度宽度,返回面积*/ function f2(int width, int height) returns (int square) { if (width < 0 || height < 0) throw; int result = width * height; LogInt(result); return result; }
/*输入N,计算N的阶乘,循环实现*/ function f3(uint n) returns (uint jiecheng) { if (n == 0) throw; uint result = 1; for (uint i=1; i<=n; i++) { result *= i; } return result; }
/*计算从1到N的求和*/ function f4(uint n) returns (uint sum) { if (n == 0) throw; uint result = 0; for (uint i=0; i<=n; i++) { result +=i; } return result; }}
下一章我们将介绍一个简化版的代币合约,敬请期待!
---------------------------------------------------------------------------------------------------------------先从最小化的Token合约开始;
之前有说过,solidity是类js的语言,和所有的面向对象语言一样,solidity也拥有最基本的构造函数。 上面的代码就是一个最简单化的一个Token合约,pragma solidity 0.4.9;contract Token { function Token() {
}}
function Token() {}
是该
contract
的构造函数。
该合约在browser-solidity上可以执行成功,这里就不演示了。
我们给这个Token代币合约添加一个数字数组,并赋予一个初值。
这个合约很简单,先定义了一个pragma solidity 0.4.9;
contract Token2 { uint[] public balancesOf; function Token() { balancesOf.push(100); balancesOf.push(200); }}
public
的变量
balancesOf
, 然后在构造阶段,就给这个变量添加两个初始值。
100
&
200
用户先点击Token这个构造函数,然后再输入0和1,然后点击balancesOf 可以分别看到两个数值。
给该Token合约添加一个账户转账功能 transfer()
transfer功能的代码就是把一定量pragma solidity 0.4.9;contract Token3 { uint[] public balancesOf; function Token() { balancesOf.push(100); balancesOf.push(200); }
function transfer(uint _from, uint _to, uint _amount) { balancesOf[_from] -= _amount; balancesOf[_to] += _amount; }}
_amount
从
_from
转移到
_to
;
该功能在browser solidity调试成功,如下图所示:
给Token代币合约,增加一个挖矿方法 mint()
如上面的代码所示,我们可以看到,只有在构造函数的时候balancesOf才有赋值,之后的transfer无论如何操作,总量始终不变。因此我们可以增加一个挖矿方法,增加的金额默认都归纳到第一个账号中 balancesOf[0]中。通过pragma solidity 0.4.9;
contract Token4 { uint[] public balancesOf; function Token() { balancesOf.push(100); balancesOf.push(200); }
function transfer(uint _from, uint _to, uint _amount) { balancesOf[_from] -= _amount; balancesOf[_to] += _amount; }
function mint(uint value) { balancesOf[0] += value; }}
mint()
我们就可以随意的给balancesOf[0] 增加代币了。该代码有兴趣的同学,请在browser-solidity上实验。
注意以上代码只用于学习使用,很多场景还未考虑,例如transfer中没有考虑_amount>当前账户余额的场景。不可用于商业化应用。
本文初步介绍了Token的核心功能,包括构造,挖矿、转账等。
但是,我们知道以太坊的核心是账户体系和智能合约,真正有意义的是在各个账户之间可以流通的代币合约。有了这些代币,我们才能用于众筹、众包等各种商业应用的实现。下篇将介绍一个包含账户的代币合约
------------------------------------------------------------------------------------------------------------------------------基于账户地址的Token合约
pragma solidity 0.4.9;contract Token { mapping (address => uint) public balancesOf; function Token() { balancesOf[msg.sender] = 10000; }}
mapping
关键词的定义
Mapping types are declared as mapping(_KeyType => _ValueType). Here _KeyType can be almost any type except for a mapping, a dynamically sized array, a contract, an enum and a struct. _ValueType can actually be any type, including mappings.
Mappings can be seen as hashtables which are virtually initialized such that every possible key exists and is mapped to a value whose byte-representation is all zeros: a type’s default value. 引用自 here
address
的定义:
address: Holds a 20 byte value (size of an Ethereum address). Address types also have members and serve as base for all contracts. members of addresses:这里的address简单地说就是geth中的账户的地址(公钥) 因此此处的代码balance
andsend
引用自 here
mapping (address => uint) balancesOf
代表定义了一个 key为address类型, value为uint类型的hashtable,名字为
balancesOf
.
所以任何在区块链私链上的账户都可以通过
balancesOf[address]
来查询他们的代币数量。
msg
的定义
msg就是指谁调用该智能合约时候发来的信息,之前说过智能合约也是一个账户。因此在以太坊中调用智能合约从底层看来就是一个账户给智能合约账户发送了一个transaction,里面包含了谁发送的,发送了多少以太币,发送了多少gas 下面是msg的一些变量
msg.data (bytes): complete calldata msg.gas (uint): remaining gas msg.sender (address): sender of the message (current call) msg.sig (bytes4): first four bytes of the calldata (i.e. function identifier) msg.value (uint): number of wei sent with the message 引用自 here最主要的就是msg.sender,代表那个账户调用该智能合约。msg.value
-
因此
balancesOf[msg.sender] = 10000;
代表给msg.sender也就是创建该合约的地址赋予一个初始值 10000;
一个带transfer & 挖矿的Token合约
pragma solidity 0.4.9;contract Token { mapping (address => uint) public balancesOf; address public owner; function Token() { owner = msg.sender; balancesOf[msg.sender] = 10000; }
function transfer(address _to, uint _value) { if (balancesOf[msg.sender] < _value) throw; //避免转移出去的代币超过当前的存货 if (balancesOf[_to] + _value < balancesOf[_to]) throw; //避免自己调用自己,或者递归调用 balancesOf[msg.sender] -= _value; balancesOf[_to] += _value; }
function mint(uint _amount) { balancesOf[owner] += _amount; }}
- 在上面的代码中,我们设置一个public owner, 保存下创建合约的msg.sender, 记录下创建者的地址。
-
在
function transfer()
中,我们设置了两个条件,避免转移出去的代币超过存货的情况,以及自己转移给自己的问题。 -
在
function mint()
中,我们给合约的owner增加我们定义的代币。从而让其方便的分给别人。
以上合约代码在Browser-solidity上调试通过,查看下图
-
我们在代码中将
owner = msg.sender
,因此owner就是创建合约的地址。我们可以看到balancesOf[owner]
的数据为10000,和代码相同。
-
调用方法
mint(500)
,自动给balancesOf[owner] += 500;
查看存额从10000增加到10500.
-
调用方法
transfer("0xccccc",300)
, 可以看到owner的存额减少300,balancesOf[“0xccccc”]增加300.
这个合约实现了最简化的代币功能,但在browser-solidity中我们可以看到一个很明显的问题,那就是没有和我们在第二部分中所搭建的geth中的几个以太坊账号结合起来。
下一章我们将介绍另一个非常有用的工具Mist,从而将智能合约、Geth、Mist结合起来。真正在以太坊私有链上运行智能合约。
本文链接:
https://www.8btc.com/article/122337
转载请注明文章出处
专访 Mable Jiang:复盘 Multicoin 投资方法论与 DeFi 洞察
原文标题:《对话 Mable:复盘 Multicoin Capital 的投资方法论与 DeFi 观察 | 链捕手》受访者:Mable Jiang,Multicoin Capital 执行董事撰文:王...
信标链、PoS、分片……接触以太坊 2.0 得先理解这些术语
原文标题:《以太坊 2.0 术语库》整理:ETH 中文网Attestation 证明证明是指验证者所发起的投票,由验证者的签名聚合而成,用以证明区块的有效性,投票通过验证者的余额进行加权。Attest...
手把手教你搭建 IPFS 私有网络
在联盟链的场景下,IPFS 作为去中心化存储的首选方案,本文将介绍如何使用 go-ipfs 搭建一个私有网络并进行简单使用。...