螞蟻區(qū)塊鏈第11課 以住房租賃積分管理系統(tǒng)為例講透螞蟻Solidity語言差異精要

1,摘要

本文以住房租賃積分管理系統(tǒng)為例宏悦,給大家演示CLOUD IDE如何編譯調(diào)試solidity智能合約,并以此為例,給大家分享以太坊SOLIDITY跟螞蟻區(qū)塊鏈SOLIDITY語言的差異點(diǎn)看疙。

2,住房租賃積分管理系統(tǒng)的背景和目標(biāo)

背景

基于區(qū)塊鏈智能合約的住房租賃積分管理系統(tǒng)旨在有效地服務(wù)于公眾群體直奋、市民能庆,真正讓那些為城市當(dāng)前發(fā)展做出努力的人有房住、租得起脚线,讓那些為城市建設(shè)長(zhǎng)遠(yuǎn)發(fā)展做出貢獻(xiàn)的人有房產(chǎn)搁胆、買得起。為此邮绿,建立住房租賃積分制度渠旁,從住房租賃市場(chǎng)主體屬性、政策激勵(lì)船逮、租賃行為三方面顾腊,運(yùn)用區(qū)塊鏈、大數(shù)據(jù)等前沿技術(shù)挖胃,建立科學(xué)杂靶、有效的住房租賃積分全生命周期管理機(jī)制梆惯,營(yíng)造活力、健康吗垮、有序垛吗、可持續(xù)的住房租賃生態(tài)。

目標(biāo)

通過使用區(qū)塊鏈平臺(tái)作為底層數(shù)據(jù)支撐抱既,確保隱私保護(hù)和數(shù)據(jù)不可篡改职烧,達(dá)到公平、公正防泵、透明的目的蚀之;利用積分決策引擎,結(jié)合住房租賃積分評(píng)價(jià)體系捷泞,產(chǎn)出應(yīng)用于住房租賃場(chǎng)景的綜合積分方案足删。該方案具備橫向擴(kuò)展性,在底層技術(shù)锁右、數(shù)據(jù)不變的基礎(chǔ)上失受,未來能夠支撐經(jīng)濟(jì)信用積分、綠色生活積分等諸多積分體系的建設(shè)咏瑟,從而擴(kuò)展形成城市信用體系拂到,應(yīng)用于如醫(yī)療教育、金融借貸码泞、綠色生活等諸多場(chǎng)景兄旬。

3,合約設(shè)計(jì)

權(quán)限管理

在住房租賃積分管理系統(tǒng)中余寥,主要分為 4 種角色领铐,分別是管理者、操作者宋舷、觀察者以及市民绪撵。管理者、操作者祝蝠、觀察者是智能合約的操作人員音诈,每個(gè)角色可以對(duì)應(yīng)多名人員。市民是租賃積分智能合約服務(wù)的對(duì)象绎狭,是整個(gè)智能合約的核心用戶细溅。

角色操作權(quán)限

  • 管理者是合約的超級(jí)管理員,能夠?qū)芾碚叻夭怼⒉僮髡咭约坝^察者進(jìn)行添加谒兄、刪除摔桦、查詢操作社付。
  • 操作者可以查詢操作者信息承疲。
  • 觀察者可以查詢觀察者信息。
1

積分操作權(quán)限

  • 管理者:具有積分獎(jiǎng)勵(lì)鸥咖、積分查詢燕鸽、積分轉(zhuǎn)移、積分違規(guī)扣除啼辣、積分權(quán)益兌換等積分操作權(quán)限啊研。
  • 操作者:操作者是由管理者設(shè)置的積分操作角色,該角色可以是具體的人員也可以是系統(tǒng)服務(wù)鸥拧,具有積分獎(jiǎng)勵(lì)党远、積分轉(zhuǎn)移、積分違規(guī)扣除富弦、積分權(quán)益兌換等積分操作權(quán)限沟娱。
  • 觀察者:觀察者是由管理者設(shè)置的積分查詢角色,該角色可以是具體的人員也可以是系統(tǒng)服務(wù)腕柜,具有積分查詢的操作權(quán)限济似。
  • 市民:市民是住房租賃積分系統(tǒng)的用戶,是住房租賃積分系統(tǒng)的實(shí)際權(quán)益對(duì)象盏缤。
    • 市民可以通過組織機(jī)構(gòu)的租賃積分外部服務(wù)系統(tǒng)代理的觀察者權(quán)限查看自己的積分狀況砰蠢。
    • 租賃積分外部服務(wù)系統(tǒng)會(huì)根據(jù)市民的合規(guī)表現(xiàn),通過操作者的權(quán)限進(jìn)行積分獎(jiǎng)勵(lì)或積分違規(guī)扣除唉铜。
    • 市民可以通過租賃積分外部服務(wù)系統(tǒng)代理的操作者權(quán)限進(jìn)行積分權(quán)益兌換或積分轉(zhuǎn)移操作台舱。
2

積分管理

租賃積分智能合約提供的服務(wù)方法包括 積分獎(jiǎng)勵(lì)積分查詢打毛、積分權(quán)益兌換柿赊、積分違規(guī)扣除積分轉(zhuǎn)移 以及積分達(dá)到閾值后觸發(fā) 積分事件幻枉。

3

積分獎(jiǎng)勵(lì)(awardScore)

在市民租賃房屋的過程中碰声,針對(duì)租賃的時(shí)間喉刘、租賃過程中產(chǎn)生的行為抒线,為市民進(jìn)行積分累計(jì)。

積分查詢(queryScore)

市民可通過租賃積分外部服務(wù)系統(tǒng)代理的觀察者權(quán)限查看自己的積分狀況杠纵。

積分權(quán)益兌換(exchangeScore)

市民的積分達(dá)到指定閾值后可以享有相應(yīng)的權(quán)益椿肩,如租房?jī)?yōu)惠瞻颂、買房資格、落戶資格等郑象。

積分違規(guī)扣除(deductScore)

在市民租賃房屋的過程中贡这,針對(duì)租賃過程中產(chǎn)生的錯(cuò)誤行為,對(duì)市民懲罰性的扣減積分厂榛。住房租賃積分作為正向激勵(lì)的積分體系盖矫,鼓勵(lì)民眾積極向上丽惭。對(duì)于積分主體的偽造資料行為,視情節(jié)嚴(yán)重程度扣減積分辈双、取消積分資格以及收回積分對(duì)應(yīng)的權(quán)益责掏。

積分事件(SCORE_EQUITY_NOTICE)

當(dāng)積分權(quán)益實(shí)時(shí)增加時(shí),會(huì)觸發(fā)積分權(quán)益檢查湃望。若積分達(dá)到了指定的閾值换衬,則會(huì)產(chǎn)生相應(yīng)的積分權(quán)益通知事件。通過外部服務(wù)系統(tǒng)通知到具體的市民证芭。

積分轉(zhuǎn)移(transferScore)

當(dāng)市民因工作關(guān)系瞳浦、家庭因素需要到其他城市生活時(shí),可以將該城市的積分轉(zhuǎn)移到目標(biāo)城市的積分系統(tǒng)废士。為滿足該合約的調(diào)用术幔,目標(biāo)合約需要有對(duì)應(yīng)的積分獎(jiǎng)勵(lì)方法(awardScore),且需要為發(fā)起合約提供操作權(quán)限湃密,即將發(fā)起合約的地址設(shè)置為操作者或管理員诅挑。

4,智能合約代碼

pragma solidity ^0.4.20;
 
contract LeasingScoreManager {
    identity[] adminList;
    identity[] observerList;
    identity[] calculatorList;
 
    //用于記錄管理數(shù)組被置位元素
    uint adminDeled;
    uint observerDeled;
    uint calculatorDeled;
 
    mapping (bytes32 => uint) leasingScore;
 
    enum ScoreAction {
        //獎(jiǎng)勵(lì)積分泛源, 因相關(guān)行為拔妥,進(jìn)行積分獎(jiǎng)勵(lì)
        ActionAwardScore,
        //積分權(quán)益兌換,花費(fèi)指定積分
        ActionExchangeScore,
        //扣除積分达箍, 因違規(guī)等没龙, 扣除積分
        ActionDeductScore,
        //查詢積分
        ActionQueryScore
        //積分轉(zhuǎn)移, 將積分轉(zhuǎn)移到其他的合約。
    }
 
    enum UserRole {
        RoleAdmin, //管理員
        RoleCalculator, //積分操作員
        RoleObserver, //積分查看人員
        RolePlayer //積分參與者
    }
 
    //是否為有效的操作人
    event VALID(bool valid, UserRole role);
    //admin/observer/calculator 用戶存在
    event USER_EXIST(bool exist, UserRole role);
    //積分事件
    event SCORE_OPERATOR(ScoreAction action, string describe);
    //積分操作錯(cuò)誤
    event SCORE_ERROR(ScoreAction action, string describe);
    //積分權(quán)益通知
    event SCORE_EQUITY_NOTICE(string action, uint score, string describe);
 
    constructor() public {
        adminList.push(msg.sender);
        adminList.push(this);
    }
 
    function indexAdmin(identity admin) view returns (uint) {
        for (uint i = 0; i < adminList.length; i++) {
            if (adminList[i] == admin) {
                return i;
            }
        }
        return adminList.length;
    }
 
    function validAdmin(identity admin) view returns (bool) {
        return indexAdmin(admin) < adminList.length;
    }
 
    function indexCalculator(identity calculator) view returns (uint) {
        for (uint i = 0; i < calculatorList.length; i++) {
            if (calculatorList[i] == calculator) {
                return i;
            }
        }
        return calculatorList.length;
    }
 
    function validCalculator(identity calculator) view returns (bool) {
        return indexCalculator(calculator) < calculatorList.length;
    }
 
    function indexObserver(identity observer) view returns (uint) {
        for (uint i = 0; i < observerList.length; i++) {
            if (observerList[i] == observer) {
                return i;
            }
        }
        return observerList.length;
    }
 
    function validObserver(identity observer) view returns (bool) {
        return indexObserver(observer) < observerList.length;
    }
 
    modifier onlyAdmin {
        bool isValid = validAdmin(msg.sender);
        emit VALID(isValid, UserRole.RoleAdmin);
        require(isValid);
        _;
    }
 
    modifier onlyCalculatorOrAdmin {
        bool isValid = validAdmin(msg.sender);
        if(isValid) {
            emit VALID(isValid, UserRole.RoleAdmin);
        } else {
            isValid = validCalculator(msg.sender);
            emit VALID(isValid, UserRole.RoleCalculator);
        }
        require(isValid);
        _;
    }
 
    modifier onlyObserverOrAdmin {
        bool isValid = validAdmin(msg.sender);
        if(isValid) {
            emit VALID(isValid, UserRole.RoleAdmin);
        } else {
            isValid = validObserver(msg.sender);
            emit VALID(isValid, UserRole.RoleObserver);
        }
        require(isValid);
        _;
    }
 
    function addAdmin(identity admin) public onlyAdmin {
        bool isExist = validAdmin(admin);
        emit USER_EXIST(isExist, UserRole.RoleAdmin);
        require(!isExist);
        if(adminDeled > 0) {
            uint deled = 1;
            for (uint i = 0; i < adminList.length; i++) {
                if(deled&adminDeled != 0) {
                    adminList[i] = admin;
                    adminDeled ^= deled;
                    break;
                }
                deled <<= 1;
            }
        } else {
            adminList.push(admin);
        }
    }
 
    function removeAdmin(identity admin) public onlyAdmin {
        uint index = indexAdmin(admin);
        bool isValid = index != adminList.length;
        emit USER_EXIST(isValid, UserRole.RoleAdmin);
        require(isValid);
        delete adminList[index];
        adminDeled ^= 1 << index;
    }
 
    function queryAdmins() view public onlyAdmin returns (identity[]) {
        return adminList;
    }
 
    function addCalculator(identity calculator) public onlyAdmin {
        bool isExist = validCalculator(calculator);
        emit USER_EXIST(isExist, UserRole.RoleCalculator);
        require(!isExist);
        if(calculatorDeled > 0) {
            uint deled = 1;
            for (uint i = 0; i < calculatorList.length; i++) {
                if(deled&calculatorDeled != 0) {
                    calculatorList[i] = calculator;
                    calculatorDeled ^= deled;
                    break;
                }
                deled <<= 1;
            }
        } else {
            calculatorList.push(calculator);
        }
    }
 
    function removeCalculator(identity calculator) public onlyAdmin {
        uint index = indexCalculator(calculator);
        bool isValid = index < calculatorList.length;
        emit USER_EXIST(isValid, UserRole.RoleCalculator);
        require(isValid);
        delete calculatorList[index];
        calculatorDeled ^= 1 << index;
    }
 
    function queryCalculators() view public onlyCalculatorOrAdmin returns (identity[]) {
        return calculatorList;
    }
 
    function addObserver(identity observer) public onlyAdmin {
        bool isExist = validObserver(observer);
        emit USER_EXIST(isExist, UserRole.RoleObserver);
        require(!isExist);
        if(observerDeled > 0) {
            uint deled = 1;
            for (uint i = 0; i < observerList.length; i++) {
                if(deled&observerDeled != 0) {
                    observerList[i] = observer;
                    observerDeled ^= deled;
                    break;
                }
                deled <<= 1;
            }
        } else {
            observerList.push(observer);
        }
    }
 
    function removeObserver(identity observer) public onlyAdmin {
        uint index = indexCalculator(observer);
        bool isValid = index < observerList.length;
        emit USER_EXIST(isValid, UserRole.RoleObserver);
        require(isValid);
        delete observerList[index];
        observerDeled ^= 1 << index;
    }
 
    function queryObservers() view public onlyObserverOrAdmin returns (identity[]) {
        return observerList;
    }
 
    function checkScoreEquity(uint balance, uint score) {
        uint total = balance + score;
        if(total >= 100 && balance < 100) {
            emit SCORE_EQUITY_NOTICE("RentConcessions", total, "Citizens enjoy a 90% discount on rental housing");
        }
        if(total >= 200 && balance < 200) {
            emit SCORE_EQUITY_NOTICE("RentConcessions_1", total, "Citizens enjoy a 80% discount on rental housing");
        }
        if(total >= 300 && balance < 300) {
            emit SCORE_EQUITY_NOTICE("PurchaseDiscount", total, "Citizens enjoy a 90% discount on purchase housing");
        }
    }
 
    //積分獎(jiǎng)勵(lì)
    function awardScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin {
        uint balance = leasingScore[player];
        leasingScore[player] = balance + score;
        emit SCORE_OPERATOR(ScoreAction.ActionAwardScore, describe);
        checkScoreEquity(balance, score);
    }
 
    //積分權(quán)級(jí)兌換缎玫,為消費(fèi)者主動(dòng)意愿硬纤,若不夠花,則不扣除積分赃磨,且發(fā)送失敗事件筝家。
    function exchangeScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin returns (bool) {
        emit SCORE_OPERATOR(ScoreAction.ActionExchangeScore, describe);
        if(leasingScore[player] >= score) {
            leasingScore[player] -= score;
            return true;
        }
        emit SCORE_ERROR(ScoreAction.ActionExchangeScore, "Score not enough to exchange");
        return false;
    }
 
    //積分扣除,為消費(fèi)者被動(dòng)意愿邻辉,進(jìn)行強(qiáng)制積分扣除溪王,若積分不夠,則清零值骇,且發(fā)送失敗時(shí)間
    function deductScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin {
        emit SCORE_OPERATOR(ScoreAction.ActionDeductScore, describe);
        uint balance = leasingScore[player];
        if(balance >= score) {
            leasingScore[player] -= score;
        } else {
            if(balance != 0) {
                leasingScore[player] = 0;
            }
            emit SCORE_ERROR(ScoreAction.ActionDeductScore, "Score not enough to deduct");
        }
    }
 
    //積分查詢
    function queryScore(bytes32 player, string describe) view public onlyObserverOrAdmin returns (uint) {
        emit SCORE_OPERATOR(ScoreAction.ActionQueryScore, describe);
        return leasingScore[player];
    }
 
    //拼接字符串
    function stringAdd(string a, string b) returns(string){
        bytes memory _a = bytes(a);
        bytes memory _b = bytes(b);
        bytes memory res = new bytes(_a.length + _b.length);
        for(uint i = 0;i < _a.length;i++)
            res[i] = _a[i];
        for(uint j = 0;j < _b.length;j++)
            res[_a.length+j] = _b[j];  
        return string(res);
    }
 
    //積分轉(zhuǎn)移莹菱,將積分從一個(gè)一個(gè)合約轉(zhuǎn)移到另一個(gè)合約
    function transferScore(bytes32 player, uint score, LeasingScoreManager toContract, string describe) public onlyCalculatorOrAdmin {
        //判斷積分是否夠用并扣除
        describe =  stringAdd("Transfer score: ", describe);
        require(exchangeScore(player, score, describe));
        toContract.awardScore(player, score, describe);
    }
}

5,合約編譯/部署/測(cè)試

5.1 賬號(hào)信息

參考《螞蟻區(qū)塊鏈第8課 如何創(chuàng)建新的賬戶吱瘩,獲取私鑰和identity標(biāo)識(shí)道伟?》 文章獲得輝哥需要的賬號(hào)的解密私鑰和identity。

角色定義如下使碾,其中的私鑰已被輝哥篡改過了蜜徽,防止被誤用裹芝。

管理者 - test002  identity: 0xd6b1f9e8a0da740fa04245a41b78eba7be9214cf96e7f6594899706e64050d20
管理者 - ella  identity: 0xfb2cb45b6b443241e38145b6445a6e0ebee0410d19e71d9fd0adf5fc382d49e5
私鑰:0x2ac3bc8673454b6de00fc8815b5f2676084d2e6c74d3a0fdf34b5e63ead6e019
操作員 - duncanwang identity: 0x4983bcbaf60b9c90dc9d9a0b38a8931aad9a444acaa2adcbc61c5e3e218c49e1 
私鑰:0x46f9c8c5037a92d7fd811b350a42dc63591fb772ea2c104b89ccb48e1784c76c
觀察員 - ouyang identity: 0xe26ef3b9bb0244244935f0176e2e4b5b623be3634276ee897810a380ae8c1314
私鑰:0x2bc3bc8673454a6de00fc8815b5f2676084d2e6c74d3a0fdf34b5e63ead6e019
市民 - dingheng identity: 0xccaa69e5e5583f2e34885450669c518a6febcdec9040a4d0a2d41cd9f8f8ca40
私鑰:0x2bc3bc8673454a6de00fc8815b5f2676084d2e6c74d3a0fdf34b5e63ead6e019

因?yàn)槟壳?2019.04.06)螞蟻BAAS系統(tǒng)存在一個(gè)BUG,導(dǎo)致ella等賬號(hào)不能被用于智能合約部署娜汁,輝哥目前可使用的賬號(hào)只有test002和duncanwang賬號(hào),輝哥在測(cè)試用例設(shè)計(jì)上做了一個(gè)小調(diào)整兄朋。

5.2 合約編譯/部署

參考《螞蟻區(qū)塊鏈第5課 如何配置Cloud IDE證書并進(jìn)行Solidity智能合約調(diào)試掐禁?》 完成智能合約的編譯和部署,采用默認(rèn)的test002賬號(hào)颅和。
【告警】在螞蟻BAAS系統(tǒng)中傅事,相同的合約名稱只能使用一次。
如果該合約已部署峡扩,可按“已部署合約”根據(jù)已部署的智能合約名稱來調(diào)用合約蹭越。

調(diào)用test002部署的LeasingScoreManager合約

5.3 模擬測(cè)試(基本函數(shù)測(cè)試成功)

賬號(hào):test002
賬號(hào)identity: 0xd6b1f9e8a0da740fa04245a41b78eba7be9214cf96e7f6594899706e64050d20
創(chuàng)建 LeasingScoreManager,其合約identity: 0x64d555c5c89575982d319fe7ddd2eb1741a5d3c4386fac168ed5440958ed5044

(1)管理員test002做賬戶設(shè)置操作

<1> 管理員test002部署合約(上海合約)后增加自己為管理員
function addAdmin(identity admin) public onlyAdmin
addAdmin(0xd6b1f9e8a0da740fa04245a41b78eba7be9214cf96e7f6594899706e64050d20)

1- 管理員test002部署合約(上海合約)后增加自己為管理員

結(jié)果:

tx hash: 0x842c8d85080878942a9fa0c1f356f3284305cb0317ce5aca2ed43291d8cd1a80
log:
VALID(bool,uint8): true,0
USER_EXIST(bool,uint8): false,0

<2> 管理員test002增加操作員 duncanwang
function addCalculator(identity calculator) public onlyAdmin
addCalculator(0x4983bcbaf60b9c90dc9d9a0b38a8931aad9a444acaa2adcbc61c5e3e218c49e1)

2- 管理員test002增加操作員 duncanwang

結(jié)果:

tx hash: 0xe68c2fa466885221dba293e95f803e511ba46e9e111ef1e44e685a2df2e2269b
log:
VALID(bool,uint8): true,0
USER_EXIST(bool,uint8): false,1

<3> 管理員test002增加觀察員 duncanwang
function addObserver(identity observer) public onlyAdmin
addObserver(0x4983bcbaf60b9c90dc9d9a0b38a8931aad9a444acaa2adcbc61c5e3e218c49e1)

3-管理員test002增加觀察員 duncanwang

結(jié)果:未記錄教届。

賬號(hào)切換到duncanwang賬號(hào):

7.切換到duncanwang賬號(hào)

(2) 操作員duncanwang給市民dingheng增加100積分响鹃,理由:在馬路上勇敢扶起一位摔倒的80歲老奶奶。

function awardScore(bytes32 player, uint score, string describe)
awardScore("dingheng",100, "理由:dingheng在馬路上勇敢扶起一位摔倒的80歲老奶奶案训。")


8.增加積分

輸出信息:

tx hash:0x591daac5d038de4d9a3f437dd8aeea466772b28562792225be3d5af2903ef122
log
VALID(bool,uint8): true,1
SCORE_OPERATOR(uint8,string):0,理由:dingheng在馬路上勇敢扶起一位摔倒的80歲老奶奶买置。
SCORE_EQUITY_NOTICE(string,uint256,string): RentConcessions,100,Citizens enjoy a 90% discount on rental housing

(3) 操作員duncanwang收到市民dingheng申請(qǐng),理由:需要租房1年强霎,花費(fèi)80積分忿项。

function exchangeScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin returns (bool)
exchangeScore("dingheng", 80, "理由:需要租房1年,花費(fèi)80積分城舞。")

9.租房花費(fèi)積分

輸出信息:

tx hash:0xd7ce3c91a3b6e3c05117616c4d6e4ad1bc05e5ba8dd016189223a81dbdc0b68a
log
VALID(bool,uint8): true,1
SCORE_OPERATOR(uint8,string): 1,理由:需要租房1年轩触,花費(fèi)80積分。

(4)操作員duncanwang發(fā)現(xiàn)市民dingheng房租到期后家夺,未及時(shí)退租脱柱。扣10個(gè)積分拉馋,電話催丁恒來退租褐捻。

function deductScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin
deductScore("dingheng", 10, "理由:dingheng房租到期后,未及時(shí)退租椅邓∧眩扣10個(gè)積分。")

10 租房到期未退租扣除積分

輸出信息:

tx hash:0x970e9ad61dfd9e264cd1bd12ca0d8426d1bbe9a178b0ec88d82d6a30ec2c5c99
log:
VALID(bool,uint8): true,1
SCORE_OPERATOR(uint8,string): 2,理由:dingheng房租到期后景馁,未及時(shí)退租板壮。扣10個(gè)積分合住。

6绰精,螞蟻BAAS Solidity語法差異精要

6.1 合約數(shù)據(jù)類型

螞蟻區(qū)塊鏈合約平臺(tái)基本支持 Solidity 所有的數(shù)據(jù)類型撒璧,但是對(duì)于一些用戶編寫的合約的輸入?yún)?shù)類型并沒有完全的支持,比如參數(shù)輸入中二維數(shù)組的輸入笨使。同時(shí)卿樱,螞蟻區(qū)塊鏈合約平臺(tái)提供了 identity 類型來標(biāo)注每一個(gè)用戶的身份,不支持原生 Solidity 中的 address 類型硫椰,identity 的長(zhǎng)度為 32 字節(jié)繁调。
螞蟻BAAS的identity就是賬號(hào)名稱的SHA256算法產(chǎn)生的32字節(jié)內(nèi)容。
例如靶草,在站長(zhǎng)工具網(wǎng)站http://tool.chinaz.com/tools/hash.aspx中輸入賬號(hào)名字duncanwang,獲得其identity為0x4983bcbaf60b9c90dc9d9a0b38a8931aad9a444acaa2adcbc61c5e3e218c49e1

image.png

更多信息奕翔,可查看 Solidity 官網(wǎng)關(guān)于類型的文檔(英文)宾袜。

6.2 合約關(guān)鍵字

螞蟻區(qū)塊鏈合約平臺(tái)支持的 Solidity 語法基本與官方文檔一致,具體語法介紹可參看 Solidity 官方文檔(英文)

本文主要介紹 Solidity 合約函數(shù)構(gòu)造的常用 權(quán)限關(guān)鍵字修飾關(guān)鍵字节视。

6.3 平臺(tái)接口函數(shù)

螞蟻區(qū)塊鏈合約平臺(tái)為合約開發(fā)者提供一些新的特性接口支持,包括對(duì)區(qū)塊數(shù)據(jù)獲取假栓、交易數(shù)據(jù)獲取寻行、加密方法的支持。

區(qū)塊數(shù)據(jù)接口函數(shù)

  • block.blockhash(uint blockNumber) returns (bytes32):傳入 blockNumber匾荆,返回塊的哈希值拌蜘。
  • block.gaslimit (uint):系統(tǒng)中的 gas 最大值。
  • block.number (uint):當(dāng)前塊高度牙丽。
  • block.timestamp (uint):當(dāng)前區(qū)塊創(chuàng)建的時(shí)間戳简卧。
  • now (uint):block.timestamp 的別名。

交易數(shù)據(jù)接口函數(shù)

  • msg.data (bytes):用戶的輸入數(shù)據(jù)烤芦。
  • msg.gas (uint):用戶交易中的 gas 值举娩。
  • msg.sender (identity):用戶交易中的發(fā)送方。
  • msg.sig (bytes4):用戶交易輸入數(shù)據(jù)的前四字節(jié)。
  • msg.value (uint):用戶交易中的 gas 值铜涉。

螞蟻區(qū)塊鏈合約平臺(tái)還支持查詢交易哈希智玻,示例如下:

tx.txhash (identity)

可通過此方法獲取當(dāng)前交易的哈希值。

6.4 不支持TOKEN轉(zhuǎn)賬相關(guān)函數(shù)

【告警】不支持TOKEN芙代,不支持地址相關(guān)的轉(zhuǎn)賬函數(shù)了吊奢。

<address>.balance (uint256):
以 Wei 為單位的 地址類型 的余額。
<address>.transfer(uint256 amount):
向 地址類型 發(fā)送數(shù)量為 amount 的 Wei纹烹,失敗時(shí)拋出異常页滚,發(fā)送 2300 gas 的礦工費(fèi),不可調(diào)節(jié)滔韵。
<address>.send(uint256 amount) returns (bool):
向 地址類型 發(fā)送數(shù)量為 amount 的 Wei,失敗時(shí)返回 false掌实,發(fā)送 2300 gas 的礦工費(fèi)用陪蜻,不可調(diào)節(jié)。
<address>.call(...) returns (bool):
發(fā)出低級(jí)函數(shù) CALL贱鼻,失敗時(shí)返回 false宴卖,發(fā)送所有可用 gas,可調(diào)節(jié)邻悬。
<address>.callcode(...) returns (bool):
發(fā)出低級(jí)函數(shù) CALLCODE症昏,失敗時(shí)返回 false,發(fā)送所有可用 gas父丰,可調(diào)節(jié)肝谭。
<address>.delegatecall(...) returns (bool):
發(fā)出低級(jí)函數(shù) DELEGATECALL,失敗時(shí)返回 false蛾扇,發(fā)送所有可用 gas攘烛,可調(diào)節(jié)。

6.5 支持合約間調(diào)用

螞蟻區(qū)塊鏈合約平臺(tái)主要支持兩種合約調(diào)用方式镀首,分別為 calldelegatecall坟漱。

call

call 類型的合約調(diào)用主要是通過調(diào)用其他合約代碼獲取某個(gè)方法的調(diào)用結(jié)果。同時(shí)更哄,在執(zhí)行該合約時(shí)芋齿,被調(diào)用合約的變量會(huì)被修改(即修改的是被調(diào)用合約的內(nèi)存),調(diào)用執(zhí)行成功時(shí)返回 true成翩,失敗則返回 false觅捆。如果被調(diào)用合約不存在,則返回執(zhí)行調(diào)用合約的 fallback 函數(shù)麻敌。

函數(shù)原型

id.call(bytes4(keccak256(data), args)) returns (bool result)

請(qǐng)求參數(shù)

參數(shù) 必選 類型 說明
id identity 被調(diào)用合約 ID
data string 被調(diào)用合約方法簽名
args var 被調(diào)用合約方法傳入?yún)?shù)

返回值

參數(shù) 必選 類型 說明
result bool 方法返回值惠拭,成功為 true,否則為 false。

delegatecall

delegatecall 類型的合約調(diào)用也是調(diào)用其他合約的方法职辅,與 call 不同的是棒呛,delegatecall 修改的是合約調(diào)用方的內(nèi)存。此方法的主要目的在于讓合約能夠在不傳輸自身狀態(tài)(如 balance域携、storage)的情況下使用其他合約的代碼簇秒。delegatecall 不支持傳輸 value。

函數(shù)原型

id.delegatecall(bytes4(keccak256(data), args)) returns (bool result)

請(qǐng)求參數(shù)

參數(shù) 必選 類型 說明
id identity 被調(diào)用合約 ID
data string 被調(diào)用合約方法簽名
args var 被調(diào)用合約方法傳入?yún)?shù)

返回值

參數(shù) 必選 類型 說明
result bool 方法返回值秀鞭,成功為 true趋观,否則為 false。

7锋边,參考

(1) Solidity 合約開發(fā) https://tech.antfin.com/docs/2/101909
(2)Solidity官方中文文檔 https://solidity-cn.readthedocs.io/zh/develop/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末皱坛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子豆巨,更是在濱河造成了極大的恐慌剩辟,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件往扔,死亡現(xiàn)場(chǎng)離奇詭異贩猎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)萍膛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門吭服,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蝗罗,你說我怎么就攤上這事艇棕。” “怎么了串塑?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵欠肾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拟赊,道長(zhǎng)刺桃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任吸祟,我火速辦了婚禮瑟慈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屋匕。我一直安慰自己葛碧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布过吻。 她就那樣靜靜地躺著进泼,像睡著了一般蔗衡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乳绕,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天绞惦,我揣著相機(jī)與錄音,去河邊找鬼洋措。 笑死济蝉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的菠发。 我是一名探鬼主播王滤,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼滓鸠!你這毒婦竟也來了雁乡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤糜俗,失蹤者是張志新(化名)和其女友劉穎踱稍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吩跋,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寞射,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年渔工,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锌钮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡引矩,死狀恐怖梁丘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旺韭,我是刑警寧澤氛谜,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站区端,受9級(jí)特大地震影響值漫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜织盼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一杨何、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沥邻,春花似錦危虱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春弥雹,著一層夾襖步出監(jiān)牢的瞬間垃帅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工缅糟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挺智,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓窗宦,卻偏偏與公主長(zhǎng)得像赦颇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赴涵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容