区块链

0x03 智能合约之Solidity基础知识

2018-04-05  本文已影响34人  金牛茶馆

一个简单的例子

pragma solidity ^0.4.21;

contract SimpleAuction {
    // Parameters of the auction. Times are either
    // absolute unix timestamps (seconds since 1970-01-01)
    // or time periods in seconds.
    address public beneficiary;
    uint public auctionEnd;

    // Current state of the auction.
    address public highestBidder;
    uint public highestBid;

    // Allowed withdrawals of previous bids
    mapping(address => uint) pendingReturns;

    // Set to true at the end, disallows any change
    bool ended;

    // Events that will be fired on changes.
    event HighestBidIncreased(address bidder, uint amount);
    event AuctionEnded(address winner, uint amount);

    // The following is a so-called natspec comment,
    // recognizable by the three slashes.
    // It will be shown when the user is asked to
    // confirm a transaction.

    /// Create a simple auction with `_biddingTime`
    /// seconds bidding time on behalf of the
    /// beneficiary address `_beneficiary`.
    function SimpleAuction(
        uint _biddingTime,
        address _beneficiary
    ) public {
        beneficiary = _beneficiary;
        auctionEnd = now + _biddingTime;
    }

    /// Bid on the auction with the value sent
    /// together with this transaction.
    /// The value will only be refunded if the
    /// auction is not won.
    function bid() public payable {
        // No arguments are necessary, all
        // information is already part of
        // the transaction. The keyword payable
        // is required for the function to
        // be able to receive Ether.

        // Revert the call if the bidding
        // period is over.
        require(now <= auctionEnd);

        // If the bid is not higher, send the
        // money back.
        require(msg.value > highestBid);

        if (highestBid != 0) {
            // Sending back the money by simply using
            // highestBidder.send(highestBid) is a security risk
            // because it could execute an untrusted contract.
            // It is always safer to let the recipients
            // withdraw their money themselves.
            pendingReturns[highestBidder] += highestBid;
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
        emit HighestBidIncreased(msg.sender, msg.value);
    }

    /// Withdraw a bid that was overbid.
    function withdraw() public returns (bool) {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            // It is important to set this to zero because the recipient
            // can call this function again as part of the receiving call
            // before `send` returns.
            pendingReturns[msg.sender] = 0;

            if (!msg.sender.send(amount)) {
                // No need to call throw here, just reset the amount owing
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }

    /// End the auction and send the highest bid
    /// to the beneficiary.
    function auctionEnd() public {
        // It is a good guideline to structure functions that interact
        // with other contracts (i.e. they call functions or send Ether)
        // into three phases:
        // 1. checking conditions
        // 2. performing actions (potentially changing conditions)
        // 3. interacting with other contracts
        // If these phases are mixed up, the other contract could call
        // back into the current contract and modify the state or cause
        // effects (ether payout) to be performed multiple times.
        // If functions called internally include interaction with external
        // contracts, they also have to be considered interaction with
        // external contracts.

        // 1. Conditions
        require(now >= auctionEnd); // auction did not yet end
        require(!ended); // this function has already been called

        // 2. Effects
        ended = true;
        emit AuctionEnded(highestBidder, highestBid);

        // 3. Interaction
        beneficiary.transfer(highestBid);
    }
}

文件布局

声明引用的版本号

pragma solidity ^0.4.0;

引入其他文件

import "filename";
import * as symbolName from "filename";
import {symbol1 as alias, symbol2} from "filename";
import "filename" as symbolName;

引入路径

所有路径名都被视为绝对路径,默认从主目录下引入。要从当前文件的同一目录中导入文件x,使用import “./x”作为x
在编译中还可以使用映射源文件

import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;

solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol

solc module1:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ \
     module2:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin_old/ \
     source.sol

Remix中的映射

允许直接使用网络地址

import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;.

注释

// This is a single-line comment.

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

参考格式:Doxygen

智能合约结构

Solidity合同与面向对象语言中的类相似。每个合约都可以包含状态变量函数函数修饰符事件结构类型枚举类型的声明。此外,合同可以继承其他合同。

类型

由于Solidity是一个静态类型的语言,所以编译时需明确指定变量的类型(包括本地或状态变量)Solidity编程语言提供了一些元类型(elementary types)可以组合成复杂类型。变量也支持在表达式运算,后面有一些关于运算符执行的先后顺序说明。

类型本身包括后面讲到的值类型(Value Types),引用类型(Refrence Type),一些复杂的内置数据结构等。

值类型(Value Type)

值类型又包含:

  enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
    ActionChoices choice;
function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)]
    uint[] memory a = new uint[](7);
    bytes memory b = new bytes(len);
    // Defines a new type with two fields.
    struct Funder {
        address addr;
        uint amount;
    }
mapping(_KeyType => _ValueType)_KeyType_ValueType

删除

delete a

基本类型之间的转换

隐式转换

uint8可以转换为 uint16 and int128 to int256
但是 int8 不能转换为 uint256 ,因为uint256不能为-1

显式转换

int8  y  =  - 3 ; 
uint  x  =  uint (y );

自动会默认一个类型

uint24  x  =  0x123 ; 
var  y  =  x ;

单位和全局可用变量

Ether 单位:

wei,finney,szabo或ether

时间单位

seconds,minutes,hours,days,weeks和 years

特殊变量和函数

阻止和事务属性

错误处理(Error Handling)

数学和加密函数

地址相关

合同相关

表达式和控制结构

输入参数和输出参数

输入参数

pragma solidity ^0.4.16;

contract Simple {
    function taker(uint _a, uint _b) public pure {
        // do something with _a and _b.
    }
}

输出参数

return v

返回多个值

return (v0, v1, ..., vn)

控制结构

函数调用

this.g(8);
c.g(2);

内部函数调用

pragma solidity ^0.4.16;

contract C {
    function g(uint a) public pure returns (uint ret) { return f(); }
    function f() internal pure returns (uint ret) { return g(7) + f(); }
}

外部函数调用

pragma solidity ^0.4.0;

contract InfoFeed {
    function info() public payable returns (uint ret) { return 42; }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(address addr) public { feed = InfoFeed(addr); }
    function callFeed() public { feed.info.value(10).gas(800)(); }
}

命名的呼叫和匿名功能参数

pragma solidity ^0.4.0;

contract InfoFeed {
    function info() public payable returns (uint ret) { return 42; }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(address addr) public { feed = InfoFeed(addr); }
    function callFeed() public { feed.info.value(10).gas(800)(); }
}

省略函数参数名称

pragma solidity ^0.4.16;

contract C {
    // omitted name for parameter
    function func(uint k, uint) public pure returns(uint) {
        return k;
    }
}

通过 new 创建合同

pragma solidity ^0.4.0;

contract D {
    uint x;
    function D(uint a) public payable {
        x = a;
    }
}

contract C {
    D d = new D(4); // will be executed as part of C's constructor

    function createD(uint arg) public {
        D newD = new D(arg);
    }

    function createAndEndowD(uint arg, uint amount) public payable {
        // Send ether along with the creation
        D newD = (new D).value(amount)(arg);
    }
}

合同

函数修饰符

所有外部观察者都可以看到合约内的所有内容。private 只会阻止其他合约访问和修改信息,但在区块链之外,整个世界仍然可以看到代码。

Getter函数

编译器会自动为所有的public 函数或者变量生成 Getter函数。

添加验证( Modifier )

使用方式:

/**
     * @dev Allows owner to remove an employee.
     * @param employeeId The id of the employee.
     */
    function removeEmployee(address employeeId)
        public
        onlyOwner
        employee_exist(employeeId)
    {
        _settlePayment(employeeId);
        _totalSalary = _totalSalary.sub(employees[employeeId].salary);
        delete employees[employeeId];
    }

译自官方文档

恒定状态变量

状态变量可以声明为constant。

函数

声明 View

函数可以声明view,在这种情况下,它们保证不修改状态。

声明pure

函数可以声明为pure,在这种情况下,它们保证不读取或修改状态。

以下内容被认为是从状态中读取的:

Fallback 函数

合同可以有一个未命名的功能。这个函数不能有参数,也不能返回任何东西。如果没有其他函数与给定的函数标识符匹配(或者根本没有提供数据),它将在对合同的调用中执行。

pragma solidity ^0.4.0;

contract Test {
    // This function is called for all messages sent to
    // this contract (there is no other function).
    // Sending Ether to this contract will cause an exception,
    // because the fallback function does not have the `payable`
    // modifier.
    function() public { x = 1; }
    uint x;
}


// This contract keeps all Ether sent to it with no way
// to get it back.
contract Sink {
    function() public payable { }
}

contract Caller {
    function callTest(Test test) public {
        test.call(0xabcdef01); // hash does not exist
        // results in test.x becoming == 1.

        // The following will not compile, but even
        // if someone sends ether to that contract,
        // the transaction will fail and reject the
        // Ether.
        //test.send(2 ether);
    }
}

函数重载

允许有相同名称但是不同参数的方法共存

pragma solidity ^0.4.16;

contract A {
    function f(uint _in) public pure returns (uint out) {
        out = 1;
    }

    function f(uint _in, bytes32 _key) public pure returns (uint out) {
        out = 2;
    }
}

Events

事件方便外部进行监听。

pragma solidity ^0.4.0;

contract ClientReceipt {
    event Deposit(
        address indexed _from,
        bytes32 indexed _id,
        uint _value
    );

    function deposit(bytes32 _id) public payable {
        // Events are emitted using `emit`, followed by
        // the name of the event and the arguments
        // (if any) in parentheses. Any such invocation
        // (even deeply nested) can be detected from
        // the JavaScript API by filtering for `Deposit`.
        emit Deposit(msg.sender, _id, msg.value);
    }
}

在web3中调用事件

var abi = /* abi as generated by the compiler */;
var ClientReceipt = web3.eth.contract(abi);
var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);

var event = clientReceipt.Deposit();

// watch for changes
event.watch(function(error, result){
    // result will contain various information
    // including the argumets given to the `Deposit`
    // call.
    if (!error)
        console.log(result);
});

// Or pass a callback to start watching immediately
var event = clientReceipt.Deposit(function(error, result) {
    if (!error)
        console.log(result);
});

日志记录

log0, log1, log2, log3, log4...

pragma solidity ^0.4.10;

contract C {
    function f() public payable {
        bytes32 _id = 0x420042;
        log3(
            bytes32(msg.value),
            bytes32(0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20),
            bytes32(msg.sender),
            _id
        );
    }
}

继承(Inheritance )

详细的路径可以参考专门写继承的一个C3 Linearization 线性化python
如果想使用父类方法,需要声明 super

构造函数

同名函数为构造函数,也就是在调用的时候默认会执行的函数。可以声明为public,internal。

抽象合约

仅仅声明,没有实体

pragma solidity ^0.4.0;

contract Feline {
    function utterance() public returns (bytes32);
}

接口

接口与抽象类似,但是还有更多的限制。

pragma solidity ^0.4.11;

interface Token {
    function transfer(address recipient, uint amount) public;
}

部署在特定地址的公用函数

Using For

我理解类似apply或者中间件的意思,所有的参数使用先经过这个use 函数的处理。

contract C {
    using Set for Set.Data; // this is the crucial change
    Set.Data knownValues;

    function register(uint value) public {
        // Here, all variables of type Set.Data have
        // corresponding member functions.
        // The following function call is identical to
        // `Set.insert(knownValues, value)`
        require(knownValues.insert(value));
    }
}

优先级

Precedence Description Operator
1 Postfix increment and decrement ++, --
New expression new <typename>
Array subscripting <array>[<index>]
Member access <object>.<member>
Function-like call <func>(<args...>)
Parentheses (<statement>)
2 Prefix increment and decrement ++, --
Unary plus and minus +, -
Unary operations delete
Logical NOT !
Bitwise NOT ~
3 Exponentiation **
4 Multiplication, division and modulo *, /, %
5 Addition and subtraction +, -
6 Bitwise shift operators <<, >>
7 Bitwise AND &
8 Bitwise XOR ^
9 Bitwise OR |
10 Inequality operators <, >, <=, >=
11 Equality operators ==, !=
12 Logical AND &&
13 Logical OR ||
14 Ternary operator <conditional> ? <if-true> : <if-false>
15 Assignment operators =, |=, ^=, &=, <<=, >>=, +=, -=, *=, /=, %=
16 Comma operator ,
上一篇下一篇

猜你喜欢

热点阅读