[区块链笔记1] 入坑区块链 智能合约solidity基础

以太坊是一个分布式计算网络,提供了运行智能合约的分布式平台。
智能合约是在以太坊虚拟机上运行的应用程序。

以太坊拥有多种高级语言可以用来编写智能合约,最流行的是solidity,基于javascript。

remix ide是一个智能合约开发的IDE

第一个代码

pragma solidity ^0.4.0;	//向上兼容到0.5.0以下
contract Demo{
    string str = "hello world";
    function getStr() public view returns(string){
        return str;
    }
    function setStr(string  t_str) public{
        str = t_str;
    }
    function pureTest(string t_str) public  pure returns(string){
        return t_str;
    }
}

节省gas(或者说ether)的两个关键字
view修饰的函数可以读取状态变量但是不能改
pure修饰的函数不能改也不能读状态变量

int/uint类型
整形变量:int8/uint8~int256/uint256,步长为8,int/uint=int256/uint256,即256位二进制位

数组
固定长度字节数组:bytes1,bytes2…bytes32,步长为1,1byte=8bit;正好和int/uint位数对应
bytes类型的变量可以通过length属性访问长度

不定长字节数组bytes arr=new bytes(2);//分配两个字节数组

不定长数组长度可以改变,自动在右侧添加0x00填充
可通过push操作向后面添加数据,push的过程会自动增加数组长度

    bytes arr = new bytes(2);
    function setArr() public{
        arr[0]=0x01;   arr[1]=0x02;
    }
    function getArr() public view returns(uint){
        return arr.length;
    } 
    function pushData() public {
        //arr.length = 3;
        arr.push(0x03);
    }

string类型
string没有length属性,也不可以通过下标的方式来获取其中元素。

注意string中存储中文一个占3个字节
string转bytes

	string str="hello world";
    function getLength() public view returns (uint){
        return bytes(str).length;
    }
    function getStr() public view returns (bytes){
        return bytes(str);
    }
    function getChar() public view returns (bytes1){
        return bytes(str)[0];
    }
    function opChar() public {
        bytes(str)[0] = 'x';
    }

bytes转string

 	bytes byteStr = new bytes(2);
    function init() public {
        byteStr[0]=0x68;  
     byteStr[1]=0x65;
    }
    
    function getStr() public view returns (string){
        return string(byteStr);
    }

bytes10转string

    function bytes10ToString(bytes10 byteStr) public pure returns (string){
        uint count=0;
        for (uint i=0; i<byteStr.length; i++){
            if (byteStr[i]!=0x00){
                count++;
            }else{
                break;
            }
        }
        bytes memory bytesStr = new bytes(count);
        for (uint j=0; j<count; j++){
            bytesStr[j] = byteStr[j];
        }
        return string(bytesStr);
    }

固定长度字节数组截取

    bytes8 byteStr = 0x1234567891234567;
    function getbyte1() public view returns (bytes1){
        return bytes1(byteStr);
    }
    function getbyte10() public view returns (bytes10){
        return bytes10(byteStr);
    }

固定长度字节数组转可变长度字节数组

	bytes8 byteStr = 0x1234567891234567;
    function getDynamicStr() public view returns (bytes){
        bytes memory tStr = new bytes(byteStr.length);
        for (uint i=0; i<byteStr.length; i++){
            tStr[i] = byteStr[i];
        }
        return tStr;
    }

int/uint数组
一维固定长度数组
int[5] arr = [];
固定长度数组只可以访问length,不能改变
二维固定长度数组
int[2][3] arr;表示有3个元素,每个元素占两个int.
当在访问下标是又变成[i][j],第i行第j列

一维可变长度数组
int[] arr = [];
可变长度数组可以修改length, push元素
二维可变长度数组
int[][] arr = [[1,2], [3,4], [5,6]];
可以修改外层长度和内层长度,但是没有push方法

地址address是用uint160来存储的

	address public p;

    address public p = 0xca35b7d915458ef540ade6068dfe2f44e8fa733c;
    function getAddress() public view returns (uint160){
        return uint160(p);
    }
    uint public pData = 1154414090619811796818182302139415280051214250812;
    function getAddress2() public view returns (address){
        return address(pData);
    }    

payable关键字代表可以通过这个函数给合约地址转账,默认转账单位是位
this代表合约的地址
通过合约/账户地址的属性balance可以获取合约/账户的ether

通过外部账户向合约转账

contract Demo{
    function getBalance() payable public {
        
    }
    function showBalance() public view returns (uint){
        return uint(this.balance);
    }
    function showRandBalance(address p) public view returns (uint) {
        return uint(this.balance);
    }
}

外部账户转账给其他账户

contract Demo{
   function trans() public payable {
       address p = 0xca35b7d915458ef540ade6068dfe2f44e8fa733c;
       p.transfer(msg.value);
   }
}

外部账户转账给合约

contract Demo{
    function showBalance() public view returns(uint){
        return this.balance;
    }
    function trans2() public payable {
         this.transfer(msg.value);
    }
    function() payable {
    }
}

全局变量
msg.sender:合约的调用者(账户)的地址
msg.value:当前消息附带的以太币
block.number:当前区块块号
block.difficulty:当前块的困难度

mapping用法,注意输入地址的时候要用双引号

contract Demo{
	mapping(address => uint) idMap;
	mapping(uint => string) strMap;
	uint public pos=0;
	
	function func(string str) public {
	    pos++;
		address p = msg.sender;
		idMap[p] = pos;
		strMap[pos] = str;
	}
	function getIdByAddress(address ad) public view returns(uint){
		return idMap[ad];
	}
	function getStrById(uint id) public view returns (string) {
		return strMap[id];
	}
}

多返回值

contract Demo{
    function test(uint a, uint b) public view returns(uint res1, uint res2){
        return (a+b, a-b);
    }
    function test2(uint a, uint b) public view returns(uint res1, uint res2){
        res1 = a+b;
        res2 = a-b;
    }
}

solidity中的构造函数只能有一个
老版本中可以用和类名相同的函数名作为构造函数
新版本中可以使用关键字constructor作为构造函数

contract Demo{
    int public n;
    // function Demo() public {
    //     n = 5;
    // }
    constructor() public{
        n=6;
    }
}

require函数,当判断条件为真,继续执行下面语句;否则下面语句都不执行
modefier关键字

contract Demo{
    address public owner;
    int public n;
    constructor() public {
        owner = msg.sender;
    }
    modifier onlyOwner()  {
        require(owner == msg.sender);
        _;  //动态添加代码
    }
    
    function func(int tn) onlyOwner {
        n = tn;
    } 
}

modifier代码重用示例

contract Demo{
    uint public level=5;
    uint public flag=0;
    modifier func(uint needLevel){
        require(level>=needLevel);
        _;
    }
    function func1() func(2){
        flag=1;
    }
    function func2() func(6){
        flag=2;
    }
}

深入modifier, 执行顺序:x=1,x=3,x=5,x=4,x=2

contract Demo{
    int public x;
    modifier mod1() {
        x=1;
        _;
        x=2;
    }
    modifier mod2() {
        x=3;
        _;
        x=4;
    }
    function test() mod1 mod2 {
        x=5;
    }
}

继承使用is关键字对象可以连续继承,也可多继承:
contract son is father, mother
父类中的变量不加修饰的时候,子类中默认(public)可以访问
父类对象中的internal修饰的成员,子类中也可以访问。在合约内可访问,外部不可访问。
父类对象中的private修饰的成员,子合约中不可以访问
父类对象中的external修饰的成员不可以在合约中访问或调用,只能在合约外部访问或调用

说明
相对于C++
public->public
private->private
internal->protected
C++中的类在这里叫合约

constant在函数中的用法被抛弃,在全局变量中,只用于byte1-byte32,int,uint,string,表示数据不可被修改

public修饰的成员会默认生成getter方法,供外部调用
比如,其中的x方法就是自动生成的,但是当我们显示写了这个函数后,就不会自动生成默认的x方法了

contract Demo{
   int public x;
   function x() external view returns(int) {
       return x;
   }
}

合约的销毁

contract Demo{
   address owner;
   int x = 0;
   constructor() public {
       owner = msg.sender;
   }
   function increase() public returns (int) {
       x  = x+10;
       return x;
   }
   function destruct() public {
       if (owner == msg.sender){
           selfdestruct(owner);
       }
   }
}

结构体的使用

contract Demo{
  struct student{
      string name;
      uint grade;
  }
  function func1() public view returns (string, uint) {
      student memory t = student("name1", 100);
      return (t.name, t.grade);
  } 
  function func2() public view returns (string, uint) {
      student memory t = student({name:"name2", grade:99});
      return (t.name, t.grade);
  }
}

不能包含本身,但是可以是动态的数组或者mapping等类型
注意memory定义的结构体,不可以直接操作结构体中的mapping
但是可以操作在合约内部默认storage定义的结构体中的mapping

storage可以看成C++中的引用

contract Demo{
  struct student{
      string name;
      uint grade;
  }
  student stu;
  function test(student storage st) internal {
      student storage s = st;
      s.grade = 100;
  }
  function func() public view returns(uint) {
      test(stu);
      return stu.grade;
  }
}

memory类型的变量传递是通过指针来传递的

枚举类型
enum day{monday, thusday, wendesday}

综合示例:众筹功能代码

pragma solidity ^0.4.0;

contract Charity{
    
    struct Payer{
        address payerAddress;
        uint payMoney;
    }
    
    struct Needer{
        address neederAddress;
        uint goal;
        uint curMoney;
        
        uint payerCount;
        
        mapping(uint => Payer) map;
    }
    uint neederCount;
    mapping(uint => Needer) needMap;
    
    function newNeeder(address _neederAddress, uint _goal) public {
        neederCount++;
        needMap[neederCount] = Needer(_neederAddress, _goal, 0, 0);
    }
    
    function pay(address _address, uint _neederPos)  payable {
        Needer storage _needer = needMap[_neederPos];
        _needer.curMoney += msg.value;
        _needer.payerCount++;
        _needer.map[ _needer.payerCount] = Payer(_address, msg.value);
    }
    
    function trans(uint _neederPos){
        Needer storage _needer = needMap[_neederPos];
        if (_needer.curMoney <= _needer.goal){
            _needer.neederAddress.transfer(_needer.curMoney);
        }
    }
    function show(uint _neederPos) public view returns (uint, uint, uint) {
        Needer storage _needer = needMap[_neederPos];
        return(_needer.goal, _needer.curMoney, _needer.payerCount);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_42172261/article/details/106804403