"Der zurückgegebene Wert ist kein konvertierbarer String" (web3js & React Frontend)

Bearbeiten: Um es klar zu sagen, die Funktion getMessage () funktioniert im Remix einwandfrei. Es scheint einfach nicht mit meinem Frontend zu funktionieren.

Ich versuche, ein Frontend für meinen Vertrag einzurichten, aber wenn ich versuche, eine bestimmte Funktion aufzurufen, die eine Zeichenfolge zurückgibt, erhalte ich die folgende Fehlermeldung in meiner Webkonsole:

Error: ERROR: The returned value is not a convertible string: formatters.js:261

Der Fehler scheint aufzutreten, wenn ich die getMessageFunktion hier aufrufe (in App.js):

async componentDidMount() {
const host = await chatroom.methods.host().call();
const members = await chatroom.methods.getMembers().call();
const chatLoglength = await chatroom.methods.getMessagesLength().call();
const chatLog = [];

for (let i = 0; i < chatLoglength; i++) {
  const newMessage = await chatroom.methods.getMessage(i+1).call();
  chatLog.push(newMessage);
}

this.setState({ host, members, chatLog });
}

Ich verwende die Web3-Version 1.0.0-beta.35. Ich habe bestätigt, dass ich den Vertrag mit dem richtigen Bytecode und ABI instanziiert habe. Ich bin mir nicht sicher, warum ich Strings von anderen Funktionen zurückgeben konnte, aber nicht von dieser. Jede Hilfe wäre sehr willkommen. Code unten.

Vertrag:

pragma solidity ^0.4.25;

contract Chatroom {
address public host;
string private password;

address[] public members;
Message[] public chatLog;

mapping(uint => Message) msgIDPair;
mapping(address => bool) isMember;

struct Message {
    address author;
    string content;
}

// @notice Creates the chat-room. Host role is given to the address of the sender
// @dev The password could be inferred from the constructor argument, not strong security
// @param _password The password the host wishes to set for the chat-room
constructor(string _password) public {
    host = msg.sender;
    addMember(host); // adds host address to members array

    password = _password;
}

// @notice Send a message `(_message)` to the chat-room (must be a member)
// @param _message The content of the message to be sent
function sendMessage(string _message) external mustBeMember {
    uint msgID = chatLog.length + 1;

    msgIDPair[msgID] = Message(msg.sender, _message); // pairs message ID with Message struct object
    chatLog.push(msgIDPair[msgID]); // adds Message object to chatLog array
}

// @notice Retrieve a message via ID `(_ID)`
// @dev Returns struct of Message, use front-end to get specific properties
// @param _ID The ID assigned to the desired message
// @return The target message
function getMessage(uint _ID) public view mustBeMember returns(string) {
    return(msgIDPair[_ID].content);
}

// @notice Check if an address is a member
// @param _target The address to be checked
// @return true if the target address is a member, false otherwise
function checkMember(address _target) public view returns(bool) {
    if (isMember[_target] == true) { // returns true if address has a "true" value assigned in isMember mapping table
        return(true);
    }
    else { // returns false if address does not have a "true" value assigned in isMember mapping table
        return(false);
    }
}

modifier mustBeMember() {
    require(checkMember(msg.sender) == true);
    _;
}


// @notice Become a member the chat-room (requires `(password)`)
// @param _password The password to evaluate
function joinChat(string _password) public requirePassword(_password) {
    addMember(msg.sender);
}

// @notice Leave the chat-room (must be a member)
function leaveChat() public mustBeMember {
    require(msg.sender != host); // host cannot leave, must transfer role first

    for (uint i = 0; i < members.length; i++) { // loops through entire members array, deletes matching address
        if (members[i] == msg.sender) {
            swapReduceIndex(members, i);
        }
    }

    isMember[msg.sender] = false;
}

// @notice Add a new member address that is not already a member
// @dev This is a helper function
// @param _newMember The address to be granted membership
function addMember(address _newMember) private {
    if (isMember[_newMember] == true) { // does nothing if address is already a member
        return();
    }
    else { // adds address to isMember mapping table and pushes the address to the members array
        isMember[_newMember] = true;
        members.push(msg.sender);
    }
}

// @notice Retrieve a list of all members
// @return A list of all member addresses
function getMembers() public view returns(address[]) {
    return(members);
}

modifier requirePassword(string _password) {
    require(keccak256(password) == keccak256(_password));
    _;
}

modifier onlyHost {
    require(msg.sender == host);
    _;
}

// @notice Remove a member (requires 'host' status)
// @param _member Address of the member to be removed
function kickMember(address _member) external onlyHost {
    require(msg.sender != _member); // host cannot kick himself

    for (uint i = 0; i < members.length; i++) { // loops through entire members array, deletes matching address
        if (members[i] == _member) {
            swapReduceIndex(members, i);
        }
    }

    isMember[_member] = false;
}

// @notice Transfer 'Host' role to another member (requires 'host' status)
// @param newHost The address of the member to be granted the 'host' role.
function switchHost(address newHost) external onlyHost {
    require(checkMember(newHost));

    host = newHost;
}

// @notice Delete index of array, swap last index with deleted, remove last index
// @dev Only works with address arrays, inteded to be used as a helper function with removing member addresses
// @param array The array in which to modify
// @param _blankIndex The number of the index to be deleted
function swapReduceIndex(address[] storage array, uint _blankIndex) internal {
    delete array[_blankIndex];
    uint lastIndex = array.length-1;
    array[_blankIndex] = array[lastIndex];
    array.length--;
}

// @notice Get length of chatLog array
// @dev Useful for displaying messages on front-end
function getMessagesLength() external view returns (uint) {
  return(chatLog.length);
}

}

App.js (Formatierungsprobleme, musste Github-Link verwenden): https://github.com/PresidentPorpoise/chatroom-react/blob/master/src/App.js

Antworten (1)

Hat der mustBeMemberModifikator getMessage()etwas damit zu tun?

Ich habe festgestellt, dass die Art und Weise, wie auf Berechtigungen basierende Modifikatoren mit Ansichtsfunktionen arbeiten, etwas seltsam sein kann. Wie in sehen Sie keinen Wurf, aber Sie erhalten einige andere Daten zurück.

In diesem Fall ... erwartet der Vertrag möglicherweise eine zurückgegebene Zeichenfolge, egal was passiert, weil es sich um eine Ansichtsfunktion handelt, obwohl er tatsächlich wirft, weil er die Anforderungen an die Modifikatorberechtigung nicht erfüllt ... was bedeutet, dass er einen Wurf anstelle von a zurückgibt Schnur.

Eine kleine Ergänzung dazu: 1. Um genauer zu sein, sage ich, dass Sie diese Vertragsmethode möglicherweise nicht als Mitglied aufrufen. 2. Wird dieser Modifikator wirklich benötigt? Sie wissen, dass jeder jeden Speicher des Vertrags (einschließlich Ihrer Passwörter) sehen kann: github.com/ethereum/wiki/wiki/…
Es wird nicht wirklich benötigt, aber ich habe es aus Gründen der Komplexität hinzugefügt, weil ich dies hauptsächlich zum Üben mache. sendMessage()Wenn die Funktion jedoch in Remix funktioniert und ich die Funktion erfolgreich vom Frontend aus verwendet habe (verwendet denselben Modifikator), glaube ich nicht, dass dies das Problem ist. Ich werde es aber sicherheitshalber versuchen.
Ein Großteil der Komplexität wurde entfernt, einschließlich des onlyMembersModifikators, und es funktioniert jetzt. Nicht sicher warum, aber vielen Dank.