Solidity入门

Solidity初学

先了解一些以太坊中的术语

交易

区块链是全球共享的交易数据库。这意味着每个人都可以通过参与网络来读取数据库中的条目。如果要更改数据库中的某些内容,则必须创建一个必须被所有其他事务接受的所谓事务。事务一词表示您要进行的更改(假设您要同时更改两个值)要么根本没有完成,要么已完全应用。此外,在将事务应用于数据库时,没有其他事务可以更改它。

例如,假设有一个表以电子货币列出所有帐户的余额。如果请求从一个帐户转帐到另一个帐户,则数据库的交易性质可确保如果从一个帐户中减去该金额,则始终将其添加到另一个帐户中。如果由于某种原因无法将金额添加到目标帐户,则也不会修改源帐户。

此外,交易始终由发送方(创建者)进行加密签名。这使得保护访问数据库的特定修改变得很简单。在电子货币的示例中,简单的检查可确保只有持有该帐户密钥的人才能从该帐户中转移资金。

要克服的一个主要障碍是(用比特币术语)所谓的“双花攻击”:如果网络中存在两个都想清空一个账户的交易,会发生什么?只有一笔交易有效,通常是最先接受的一笔。问题在于,“第一”不是对等网络中的客观术语。

对此的抽象答案是您不必关心。将为您选择一个全球公认的交易顺序,以解决冲突。事务将被捆绑到一个所谓的“块”中,然后将它们执行并分布在所有参与节点之间。如果两笔交易相互矛盾,那么最后一笔交易将被拒绝,并且不会成为交易的一部分。

这些块在时间上形成线性序列,这就是“块链”一词的来源。区块以相当固定的间隔添加到链中-对于以太坊来说,这大约是每17秒一次。

作为“订单选择机制”(称为“挖矿”)的一部分,可能会不时地还原块,但只能在链的“尖端”进行。在特定块的顶部添加的块越多,还原该块的可能性就越小。因此可能是您的交易已还原甚至从区块链中删除,但是等待时间越长,发生的可能性就越小。

注意

不能保证将事务包含在下一个块或任何特定的将来的块中,因为这不是由事务的提交者决定的,而是由矿工确定将事务包括在哪个块中的。

如果要安排合同的未来调用,可以使用闹钟或类似的oracle服务。

以太坊虚拟机EVM

以太坊虚拟机或EVM是以太坊中智能合约的运行时环境。它不仅是沙盒,而且实际上是完全隔离的,这意味着在EVM中运行的代码无法访问网络,文件系统或其他进程。智能合约甚至无法访问其他智能合约。

帐户

以太坊有两种共享相同地址空间的账户:由公私钥对(即人)控制的外部账户和由与该账户一起存储的代码控制的合约账户。

外部帐户的地址是根据公钥确定的,而合同的地址是在创建合同时确定的(它是根据创建者的地址以及从该地址发送的交易次数得出的,即“随机数”)。

不管帐户是否存储代码,EVM均会平等对待这两种类型。

每个帐户都有一个永久键值存储,将256位字映射到256位字,称为storage。

此外,每个帐户都有以太币的余额(准确地说,以“ Wei”表示,1个以太币是10 ** 18 wei),可以通过发送包括以太币的交易来进行修改。

什么是Solidity?

以太坊Solidity是一种面向智能合约的高级语言,其语法与JavaScript类似。solidity是用于生成在EVM上执行的机器级代码的工具。solidity编译器获取高级代码并将其分解为更简单的指令。Solidity代码封装在Contracts中。

以太坊合约中的solidity

合约是以太坊去中心化应用程序的基本构建模块。所有变量和函数都是合约的一部分,这是所有项目的起点。一个名为MyFirst的空合约看起来像这样:

version pragma ^0.4.19;
contract MyFirst{
}

Solidity文件的布局

源文件可以包含任意数量的合约定义,包括指令和pragma指令。

Version Pragma

Version Pragma是定义代码使用的Solidity编译器版本的声明。

version pragma ^0.4.00;

注意:上面显示的源文件不会使用早于版本0.4.0的编译器进行编译,也不能在从版本0.5.0开始的编译器上运行。

导入其他源文件

Ethereum Solidity支持与JavaScript中可用的导入语句非常相似的导入语句,尽管Solidity不知道default export的概念。

在全局级别,可以使用以下形式的import语句:

import "filename";

上述语句将所有全局符号从filename导入当前全局范围。

import * as symbolName from "filename";

注释

就像任何其他语言一样,Solidity可以使用单行和多行注释。

// This is a single-line comment.
/*
This is a
multi-line comment
*/

现在,在我们进一步深入了解Solidity教程之前,应该知道以太坊有三个可以存储项目的区域。

  • 存储Storage:所有合约状态变量所在的位置。每个合约都有自己的存储,并且在函数调用之间是持久的。
  • 内存Memory:保存临时值并在(外部)函数调用之间擦除,并且使用起来更便宜。
  • 堆栈Stack:保存小的局部变量并且几乎可以免费使用,但只能保存有限数量的值。
    对于几乎所有类型,都无法指定它们应存储的位置,因为它们在每次使用时都会被复制。

好了,既然你已经知道以太坊Solidity中的存储位置,那么让我告诉你一般的值类型。

solidity中的值类型

以下类型也称为值类型,因为这些类型的变量将始终按值传递

Solidity入门_第1张图片

布尔

关键词:bool
值是常数,即true或false。

整型

关键字:int/uint(uint8到uint256,步长为8(无符号,最多为256位),int8为int256)
各种大小的有符号和无符号整数。
例:

contract MySample{
uint UnsignedInt =50;
}

在上面的语句中,我们创建了一个名为InsignedInt的uint并将其设置为50。

地址

关键字:address

保存一个20字节的值(以太坊地址的大小)。地址类型也有members,并作为所有合约的基础。

地址成员:balance与transfer

可以使用属性balance查询地址的余额,并使用transfer函数将以太网发送到地址。

address x = 0x123;
address myAddress = this;
if  (x.balance < 10 && myAddress.balance > = 10)
x.transfer(10);

字符串

String:字符串文字用双引号或单引号如“foo”或’bar’编写。
用于任意长度的UTF数据。

string language ="Solidity";

这些值类型可以在包含运算符的表达式中相互交互。接下来,在我们的Solidity教程中,让我告诉你各种运算符。

运算符

solidity的运算符与JavaScript相同。Solidity有四种类型的运算符:
Solidity入门_第2张图片

算术运算符

Solidity具有非常简单的数学运算。以下与大多数编程语言类似:

  • 增加:x + y
  • 减法:x - y
  • 乘法:x * y
  • 除法:x / y
  • 取整/求余:x%y
    Solidity还提供了使用指数运算符的选项,具体如下:
uint x = 10 **  3; // equal to 10^3 = 1000

增量运算符

增量运算符的稳定性:a++,a- ,++a,-a,a+=1,a=a+1
适用于其他编程语言的规则也是类似的。

按位运算符

以下是运算符:(按位OR)’|’,(按位异或),(按位求反)’~’,(按位右移)’>>’,(按位左移)’<<’

逻辑运算符

Solidity中的逻辑运算符:!(逻辑否定),&&(逻辑和),||(逻辑或),==(相等),!=(不相等)

例:

contract operators {
// Arithmetic Operators
// +,-,*,/, %, **
// Incremental Operators
// a++, a--, a+=1, a=a+1,++a,--a;
a=10;
a= a++; //here, output will be 10, because the value is first returned and then then increment is done
a=++a; //12
//Logical Operators
!, &&, ||, ==, !=
isOwner = true && false;
var orValue= 0x02 | 0x01; // output would be 0x03
//Bitwise Operators~,>>, <<;
function Operators() {
// Initialize state variables here}}

现在有时需要更复杂的数据类型。为此,Solidity提供结构。

solidity数据结构

Solidity提供三种类型的数据结构:
Solidity入门_第3张图片

结构Structs

Solidity提供了一种以Structs形式定义新类型的方法。Structs是自定义类型,可以对多个变量进行分组。

pragma solidity ^0.4.0;
contract Ballot {
struct Voter { // Struct
uint weight1, weight2, weight3;//uint
bool voted;//bool
address delegate1, delegate2, delegate3, delegate4;//address
string name;//string
uint vote1, vote2, vote3, vote4, vote5;//uint
uint height1, height2, height3   } }

注意:结构只能有16个成员,超过该成员可能会发生以下错误:Stack too Deep 堆栈太深。
结构允许创建具有多个属性的更复杂的数据类型。

现在,如果你需要一些集合,比如说地址,那该怎么办?好吧,就像大多数语言一样,Solidity也有数组。

数组Arrays

Solidity中的数组可以具有编译时固定大小,也可以是动态的。

uint[3] fixed;  //array of fixed length 3
uint[] dynamic; //a dynamic array has no fixed size, it can keep growing

还可以创建一个结构数组(即这个array里面的成员是struct)。使用以前创建的Voter结构:

Voter[] voting;

注意:将数组声明为public将自动为其创建getter方法。

Voter[] public voting;

注意:Voter是以太坊合约中-投票选举中的struct类型,代表广大选民,具体如下:
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}

映射mappings

映射可以看作是哈希表,它们被虚拟地初始化,使得每个可能的键都存在并被映射到其字节表示全为零的值:类型的默认值。
是一种引用类型,存储键值对,提供根据键查找值,与其它语言中的字典,map等类似,但也有非常大的不同,尤其它在区块链中独特的存储模型。
映射声明为:

Mapping(_Keytype => _ValueType )

例:

contract MappingExample {
	mapping(address => uint) public balances;
	function update(uint newBalance) {
		balances[msg.sender] = newBalance;  }}
	contract MappingUser {
		function f() returns (uint) {
			MappingExample m = new MappingExample();
			m.update(100);
			return m.balances(this);
}}

1. 只能是状态变量
由于在映射中键的数量是任意的,导致映射的大小也是变长的。映射只能声明为storage的状态变量,或被赋值给一个storage的对象引用。
我们来看下面的示例:

pragma solidity ^0.4.0;
contract StateVariableOnly{
  //状态变量
  mapping(uint => uint) stateVar;
  function mappingTest() returns (uint){
    //可以被赋值为storage的引用
    mapping(uint => uint) storageRef = stateVar;
    storageRef[1] = uint(64);
    return storageRef[1];
  }
}

在上面的示例中,我们声明了storage的状态变量stateVar,可以对其增加新键值对;也能通过引用传递的方式赋值给storage的引用storageRef。
2. 支持的类型
映射类型的键支持除映射,变长数组,合约,枚举,结构体以外的任意类型。值则允许任意类型,甚至是映射。下面是一个简单的例子代码:x

pragma solidity ^0.4.0;
contract MappingType{
  struct s{
    string name;
    uint8 age;
  }
  mapping(bytes => s) structMapping;
  mapping(address => s) addrMapping;
  mapping(string => mapping(uint => s)) complexMapping;
}

3. setter方法
对于映射类型,也能标记为public。以让Solidity为我们自动生成访问器。

pragma solidity ^0.4.0;
contract MappingGetter{
  mapping(uint => uint) public intMapp;
  mapping(uint => mapping(uint => string)) public mapMapp;
  function set(){
    intMapp[1] = 100;
    mapMapp[2][2] = "aaa";
  }
}

在上面的例子中,如果要访问intMapp[1],输入值1。而如果要访问嵌套的映射mapMapp[2][2],则输入两个键对应的值2,2即可。
4. 映射的存储模型
由于状态变量是存储在区块链上的,所以存储空间需要预先分配,但映射的存储值是可以动态增改的,那么最终是如何支持的呢。关于状态的存储模型里面提到,实际存储时是以哈希键值对的方式。其中哈希是由键值和映射的存储槽位序号拼接后计算的哈希值(映射只占一个槽位序号),也就是说值是存到由keccak256(k . p)计算的哈希串里,这里的k表示的是映射要查找的键,p表示映射在整个合约中相对序号位置。
更多关于mapping请学习这里

控制结构

除了switch和goto之外,JavaScript中的大多数控制结构都在Solidity中可用。

所以有:if,else,while,do,for,break,continue,return,? :,使用从C或JavaScript中已知的通常语义。

注意:没有像C和JavaScript那样从非布尔类型到布尔类型的类型转换。

现在让我们看看这些控制结构如何在Solidity中使用。

contract ControlStructure {
	address public a;
	function ControlStructure>){
	// if-else can be used like this
	if(input1==2)
		a=1;
	else
		a=0;
	// while can be used like this
	while(input1>=0){
		if(input1==5)
			continue;
		input1=input1-1;
		a++;}
	// for loop can be used like this
	for(uint i=0;i<=50;i++) { a++; if(a==4) break; } 
	//do while can be used like this do { a--; } (while a>0);
	// Conditional Operator can be used like this
	bool IsTrue = (a == 1)?true: false;
	/*will show an error because
	there is no type conversion from non-boolean to boolean
	*/
	if(1)
	{
	}

继续我们的Solidity教程博客,让我们谈谈合约中可执行的代码单元。这些被称为函数。

函数

以下是在Solidity中声明函数的方式。

function sampleFunc(string name, uint amount) {
}

上面声明的是一个空体函数,它有两个参数:一个字符串和一个uint。
可以这样调用此函数:

sampleFunc("Shashank", 10000);

更详细的函数介绍请点击另一篇博客

谈到函数,Solidity还提供函数修饰符。

函数修饰符

它用于轻松更改函数的行为。甚至在进行函数调用之前也可以检查这些条件,因为它们已在智能合约的函数定义中声明。
示例:如果要仅通过函数的所有者或创建者调用kill contract函数。

contract FunctionModifiers{
	address public creator;
	
	function FunctionModifiers() {
		creator = msg.sender;//msg.sender是一个实时变化的变量!在合约中,方法的调用者不一样,msg.sender就会不一样
	}
	
	//在实际情况中,我们经常需要对调用者进行一些限制。比如,只能是合约的所有者才能改变归属。
	Modifier onlyCreator() {
		if(msg.sender!=creator){
			throw; 
			_;
		}
		//resumes the function wherever the access modifier is used
	}
	
	function killContract() onlyCreator{ 
	//function will not execute if an exception occurs
		self-destruct(creator); 
	}
}

注:关于函数修改器Function Modifiers,参见文章:
Solidity的函数修改器(十九)|入门系列

继承

Solidity通过复制包含多态的代码来支持多重继承。

contract Owned {
	address Owner ;
	function owned() {
		owner = msg.sender;
	}
}

contract Mortal is Owned {  
	// 'is' keyword is used for inheritance
	function kill(){
	self-destruct(owner);   
	}
}

contract User is Owned, Mortal //Multiple inheritance
{
	string public UserName;
	function User(string _name){
		UserName = _name;
	}
}

好吧,我觉得上面讨论的概念足以让你开始使用Solidity编程。

大部分翻译自原文,中间添加了自己的理解

你可能感兴趣的:(智能合约)