Solidity
契約適用於 Remix,但不適用於松露
我有一個簡單的認證契約,可以將認證發送到區塊鏈。這是完整的契約:
pragma solidity ^0.4.2; /// @title Sending and storing certifications to the blockchain contract CertificationStore { struct Certification { string firstName; string lastName; string certName; string institution; string description; uint year; // address account; uint month; uint day; } mapping (address => Certification) public certifications; Certification[] public certArray; address[] public addressIdx; uint numCerts; event Send(address indexed _from); event logIdx(address indexed _from, string location, uint idxToLog); event logString(address indexed _from, string location, string msg); function CertificationStore() { numCerts = 0; } function getCertArrayLength() constant returns(uint) { return certArray.length; } function getAddressIdxLength() constant returns(uint) { return addressIdx.length; } function getNumberOfCerts() constant returns(uint) { return numCerts; } function sendCert(address acct, string fn, string ln, string cn, string ins, string desc, uint yy, uint mm, uint dd) returns(uint) { certifications[acct] = Certification({ firstName: fn, lastName: ln, institution: ins, description: desc, certName: cn, year: yy, month: mm, day: dd }); numCerts++; addressIdx.push(acct); certArray.push(Certification({ firstName: fn, lastName: ln, institution: ins, description: desc, certName: cn, year: yy, month: mm, day: dd })); logString(acct, "in Send Cert", "pushed to both arrays"); logIdx(acct, "in Send Cert. numCerts ", numCerts); Send(acct); return numCerts; } function getFirstName(address _from) constant returns(string) { for (uint i = 0; i < certArray.length; i++) { Certification cert = certArray[i]; string name = cert.firstName; logIdx(_from, "at index in getFirstName", i); address acct = addressIdx[i]; if(acct == _from) { return name; } } return ("no name found"); } }
用松露,我發送契約是這樣的:
sendCert: function() { var self = this; this.setStatus("Initiating certification... (Please wait)"); var meta; var myEvent; CertificationStore.deployed().then(function(instance) { meta = instance; var firstName = document.getElementById("first").value; var lastName = document.getElementById("last").value; var certName = document.getElementById("cert_name").value; var date = document.getElementById("date").value; var description = document.getElementById("description").value; var institution = document.getElementById("institution").value; var tempDate = new Date(date); return meta.sendCert(account, firstName, lastName, certName, institution, description, tempDate.getFullYear(), tempDate.getMonth()+1, tempDate.getDay(), {from: account}); }).then(function(result) { // on success alert("Your certification was successfully sent for account: " + account); console.log("result of your deployment ", result); self.setStatus("Sent your certification successfully for account: " + account); }).catch(function(e) { // on error set status console.log(e); self.setStatus("Error sending certification; see log."); }); },
我希望結果是我設置的 numCerts 變數,它會隨著添加的契約而增加。但是它返回了完整的交易結果,但沒關係。我的問題是,在 Remix 上,它返回了這個交易結果:
請注意它如何儲存我在該事務中的日誌。
當我使用上面的程式碼在本地添加認證時,這是我得到的結果:
因此,當我在 Remix 上部署此合約並執行“getCertArrayLength”和“getNumCert”函式時,它會返回正確的值:每次添加合約時它都會遞增。然而,在本地,這些值仍然為 0,即使我從 truffle 得到的結果表明我的合約已成功部署在區塊鏈上。
我對此有兩個主要困惑
1)我的本地開發日誌數組每次都是空的,有什麼原因嗎?
- remix 如何呼叫合約的函式和我如何在javascript中呼叫它有區別嗎?
預先感謝您的幫助
Q1。只是程式碼太多。
Q2。是的,有區別。
這一行:
return meta.sendCert(account, firstName, lastName, certName, institution, description, tempDate.getFullYear(), tempDate.getMonth()+1, tempDate.getDay(), {from: account}); }).then(function(result) {
這個世界可能更有意義:
then(function(txn) { ...
當您發送交易時,您沒有得到結果,而是得到了交易。
如果您想要 Remix 顯示的響應,請添加
.call()
meta.sendCert.call(...
這將返回鏈的本地副本上的本地計算結果。有一個問題。這是一個只讀事務排練。它不會改變狀態,但您會看到響應。
因此,我們要麼更改狀態並看到事務但看不到結果,要麼我們可以看到響應但它沒有粘住,下次我們檢查時它就不存在了。尷尬的。
有不止一種方法可以解決這個問題。Remix 先做
.call
,然後再做。效仿這種做法可能並不明智。當多個交易正在進行時,實際結果不一定是預演預測的結果。這就是為什麼我的偏好通常是發送一個事務,然後檢查 getter(用於測試)或偵聽事務日誌以發現結果(用於客戶端)。希望能幫助到你。