У меня есть простой контракт на сертификацию, который отправляет сертификацию в блокчейн. Это полный контракт:
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, даже несмотря на то, что я получаю результат от трюфеля, в котором говорится, что мой контракт был успешно развернут в цепочке блоков.
У меня есть две основные путаницы с этим
1) есть ли причина, по которой мой массив журналов при локальной разработке каждый раз пуст?
2) есть ли разница в том, как ремикс вызывает функции контракта и как я вызываю его в 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(...
Это вернет результат локального вычисления в локальной копии цепочки. Есть подвох. Это репетиция транзакции только для чтения. Он не меняет состояние, но вы увидите ответ.
Таким образом, мы либо меняем состояние и видим транзакцию, но не результат, либо видим ответ, но он не фиксируется и его не будет в следующий раз, когда мы проверим. Неуклюжий.
Есть несколько способов приблизиться к этому. Ремикс .call
сначала делает, а потом делает по-настоящему. Возможно, было бы неразумно подражать этому. Когда выполняется несколько транзакций, фактический результат не обязательно будет таким, как предсказывала репетиция. Вот почему я обычно предпочитаю отправлять транзакцию, а затем проверять геттеры (для тестов) или прослушивать журналы транзакций, чтобы обнаружить результаты (для клиентов).
Надеюсь, поможет.
Каран
getNumberOfCerts
и т. д., все они вернули 0, предполагая, что количество сертификатов не обновлялось (даже несмотря на то, что сертификат был отправлен, и цепочка, по-видимому, обновилась). Это странно для меня, так как они обновляются в Remix и возвращают правильное значение. Я использую.call
эти методы, так как они также доступны только для чтения.