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)行添加谒兄、刪除摔桦、查詢操作社付。
- 操作者可以查詢操作者信息承疲。
- 觀察者可以查詢觀察者信息。
積分操作權(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)移操作台舱。
積分管理
租賃積分智能合約提供的服務(wù)方法包括 積分獎(jiǎng)勵(lì)、積分查詢打毛、積分權(quán)益兌換柿赊、積分違規(guī)扣除、積分轉(zhuǎn)移 以及積分達(dá)到閾值后觸發(fā) 積分事件幻枉。
積分獎(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)用合約蹭越。
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)
結(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)
結(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)
結(jié)果:未記錄教届。
賬號(hào)切換到duncanwang賬號(hào):
(2) 操作員duncanwang給市民dingheng增加100積分响鹃,理由:在馬路上勇敢扶起一位摔倒的80歲老奶奶。
function awardScore(bytes32 player, uint score, string describe)
awardScore("dingheng",100, "理由:dingheng在馬路上勇敢扶起一位摔倒的80歲老奶奶案训。")
輸出信息:
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積分城舞。")
輸出信息:
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è)積分。")
輸出信息:
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
更多信息奕翔,可查看 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)用方式镀首,分別為 call
和 delegatecall
坟漱。
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/