【问题标题】:Building on Truffle Tutorial - Adding Return Pet Function - RPC Error以 Truffle 教程为基础 - 添加返回 Pet 函数 - RPC 错误
【发布时间】:2022-01-07 05:19:19
【问题描述】:

我正在建立在 Truffle 提供的教程之上:https://trufflesuite.com/tutorial/index.html

我正在尝试添加类似于以下内容的 returnPet 函数:Adding a return function to Truffles Pet Shop

但是,当我点击宠物上的“返回”按钮时,我在使用元掩码时遇到了 RPC 错误。

MetaMask - RPC Error: [ethjs-query] while formatting outputs from RPC '{"value":{"code":-32603,"data":{"message":"VM Exception while processing transaction: revert","code":-32000,"data":{"0x36735e441b9c6ffeb61bcebce098576993c38580ecc207f99043706a074a06e4":{"error":"revert","program_counter":70,"return":"0x"},"stack":"RuntimeError: VM Exception while processing transaction: revert\n    at Function.RuntimeError.fromResults (/tmp/.mount_ganachz4CZxO/resources/static/node/node_modules/ganache-core/lib/utils/runtimeerror.js:94:13)\n    at BlockchainDouble.processBlock (/tmp/.mount_ganachz4CZxO/resources/static/node/node_modules/ganache-core/lib/blockchain_double.js:627:24)\n    at runMicrotasks (<anonymous>)\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)","name":"RuntimeError"}}}}' 
Object { code: -32603, message: "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"VM Exception while processing transaction: revert\",\"code\":-32000,\"data\":{\"0x36735e441b9c6ffeb61bcebce098576993c38580ecc207f99043706a074a06e4\":{\"error\":\"revert\",\"program_counter\":70,\"return\":\"0x\"},\"stack\":\"RuntimeError: VM Exception while processing transaction: revert\\n    at Function.RuntimeError.fromResults (/tmp/.mount_ganachz4CZxO/resources/static/node/node_modules/ganache-core/lib/utils/runtimeerror.js:94:13)\\n    at BlockchainDouble.processBlock (/tmp/.mount_ganachz4CZxO/resources/static/node/node_modules/ganache-core/lib/blockchain_double.js:627:24)\\n    at runMicrotasks (<anonymous>)\\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)\",\"name\":\"RuntimeError\"}}}}'" }

我在这里维护这项工作:https://github.com/mpoletiek/pet-shop-tutorial

我不知道从哪里开始。在 Metamask 中批准交易之前,它会警告:

This transaction is expected to fail. Trying to execute it is expected to be expensive but fail, and is not recommended.

我单击“无论如何我都会尝试”以生成 RPC 错误。

这是我的 Solidity 合约:

pragma solidity ^0.5.0;

contract Adoption {
    address[16] public adopters;

    // Adopting a pet
    function adopt(uint petId) public returns (uint) {
        require(petId >= 0 && petId <= 15);

        adopters[petId] = msg.sender;

        return petId;
    }

    // Retrieving the adopters
    function getAdopters() public view returns (address[16] memory) {
        return adopters;
    }
    
    // Return Pet
    function returnPet(uint petId) public returns (address) {
        require(petId >= 0 && petId <= 15);
        
        // Address must own the pet
        require(msg.sender == adopters[petId]);
        
        // Clear the adopter for this pet
        adopters[petId] = address(0);
        
        return adopters[petId];
    }

}

和 app.js:

App = {
  web3Provider: null,
  accounts: [],
  contracts: {},
  adoptionInstance: null,

  init: async function() {
    // Load pets.
    $.getJSON('../pets.json', function(data) {
      var petsRow = $('#petsRow');
      var petTemplate = $('#petTemplate');

      for (i = 0; i < data.length; i ++) {
        petTemplate.find('.panel-title').text(data[i].name);
        petTemplate.find('img').attr('src', data[i].picture);
        petTemplate.find('.pet-breed').text(data[i].breed);
        petTemplate.find('.pet-age').text(data[i].age);
        petTemplate.find('.pet-location').text(data[i].location);
        petTemplate.find('.btn-adopt').attr('data-id', data[i].id);
        petTemplate.find('.btn-return').attr('data-id', data[i].id);

        petsRow.append(petTemplate.html());
      }
    });

    return await App.initWeb3();
  },

  initWeb3: async function() {

    // Modern dapp browsers...
    if (window.ethereum){
      try {
        //Request account access
        App.accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
      } catch (error) {
        // User denied account access...
        console.error("User denied account access");
      }
      
      // User granted access to accounts
      console.log("Account[0]: "+App.accounts[0]);
      
      App.web3Provider = window.ethereum;
      console.log("modern dapp browser");
    }
    // Legacy dapp browsers...
    else if (window.web3) {
      App.web3Provider = window.web3.currentProvider;
      App.accounts = window.eth.accounts;
      console.log("legacy dapp browser");
    }
    // if no injected web3 instance is detected, fall back to Ganache
    else {
      App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
    }
    
    web3 = new Web3(App.web3Provider);

    return App.initContract();
    
  },

  initContract: function() {

    $.getJSON('Adoption.json', function(data) {
      // Get the necessary contract artifact file and instantiate it with @truffle/contract
      var AdoptionArtifact = data;
      try { App.contracts.Adoption = TruffleContract(AdoptionArtifact); } catch (error) { console.error(error); }

      // Set the provider for our contract
      try {
        App.contracts.Adoption.setProvider(App.web3Provider);
      } catch (error){
        console.log(error);
      }
      // Use our contract to retrieve and mark the adopted pets
      return App.markAdopted();
    });

    return App.bindEvents();
  },

  bindEvents: function() {
    $(document).on('click', '.btn-adopt', App.handleAdopt);
    $(document).on('click', '.btn-return', App.handleReturn);
  },

  markAdopted: function() {

    var adoptionInstance;

    App.contracts.Adoption.deployed().then(function(instance) {
      App.adoptionInstance = instance;

      return App.adoptionInstance.getAdopters.call();
    }).then(function(adopters) {
        
        for(i=0;i<adopters.length;i++){
            if (adopters[i] != '0x0000000000000000000000000000000000000000') {
                if (adopters[i] == App.accounts[0]){
                    $('.panel-pet').eq(i).find('.btn-return').text('Return').attr('disabled', false);
                    $('.panel-pet').eq(i).find('.btn-adopt').text('Adopted').attr('disabled', true);
                } else {
                    $('.panel-pet').eq(i).find('.btn-return').text('-').attr('disabled', true);
                    $('.panel-pet').eq(i).find('.btn-adopt').text('Adopted').attr('disabled', true);
                }
            } else {
                $('.panel-pet').eq(i).find('.btn-return').text('-').attr('disabled', true);
            }
        }
        
        
        
    }).catch(function(err) {
      console.log(err.message);
    });
  },

  handleReturn: function(event) {
    event.preventDefault();
    
    var petId = parseInt($(event.target).data('id'));
    
    console.log("petID:"+petId);
        
    App.contracts.Adoption.deployed().then(function(instance) {

        // Execute adopt as a transaction by sending account
        return App.adoptionInstance.returnPet(petId, {from: App.accounts[0]});
      }).then(function(result) {
        return App.markAdopted();
      }).catch(function(err) {
        console.log(err.message);
      });
    
  },


  handleAdopt: function(event) {
    event.preventDefault();

    var petId = parseInt($(event.target).data('id'));
    console.log("petId:"+petId);

    App.contracts.Adoption.deployed().then(function(instance) {

        // Execute adopt as a transaction by sending account
        return App.adoptionInstance.adopt(petId, {from: account[0]});
        }).then(function(result) {
            return App.markAdopted();
        }).catch(function(err) {
            console.log(err.message);
    });
    
  }

};

$(function() {
  $(window).load(function() {
    App.init();
  });
});

一切都编译并且我的测试运行正常。在我确认之前不确定 Metamask 如何知道交易是坏的,但这是一个提示吗?如果有帮助,我会在 Firefox 和 Chrome 中得到相同的结果。

任何想法我应该首先检查什么?

谢谢,

【问题讨论】:

    标签: javascript ethereum solidity smartcontracts web3


    【解决方案1】:

    根据提供的代码,您正试图归还一只尚未被领养的宠物,因此由于此逻辑错误而失败。

    首先部署合约。由于构造函数中没有收养机制,所以这一步之后就没有收养宠物了。

    App.contracts.Adoption.deployed()
    

    然后你会立即尝试归还宠物

    return adoptionInstance.returnPet
    

    这行失败了,因为 所有 采用者此时的默认值是 0x0。

    require(msg.sender == adopters[petId]);
    

    解决方案:根据您的 JS 代码的上下文(注释和 return App.markAdopted()),您可能希望在 JS 测试中调用 adopt() 函数 - 而不是 returnPet() .

    【讨论】:

    【解决方案2】:

    所以在重置整个环境并使用truffle migrate --reset 重建后,我终于得到了这个工作。我还必须确保我只有 1 个浏览器选项卡向应用程序打开,多个选项卡会导致多笔交易,出于某种我仍然不知道的原因。

    app.js

    App = {
      web3Provider: null,
      accounts: [],
      contracts: {},
    
      init: async function() {
        // Load pets.
        $.getJSON('../pets.json', function(data) {
          var petsRow = $('#petsRow');
          var petTemplate = $('#petTemplate');
    
          for (i = 0; i < data.length; i ++) {
            petTemplate.find('.panel-title').text(data[i].name);
            petTemplate.find('img').attr('src', data[i].picture);
            petTemplate.find('.pet-breed').text(data[i].breed);
            petTemplate.find('.pet-age').text(data[i].age);
            petTemplate.find('.pet-location').text(data[i].location);
            petTemplate.find('.btn-adopt').attr('data-id', data[i].id);
            petTemplate.find('.btn-return').attr('data-id', data[i].id);
    
            petsRow.append(petTemplate.html());
          }
        });
    
        return await App.initWeb3();
      },
    
      initWeb3: async function() {
    
        // Modern dapp browsers...
        if (window.ethereum){
          try {
            //Request account access
            App.accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
          } catch (error) {
            // User denied account access...
            console.error("User denied account access");
          }
          
          // User granted access to accounts
          console.log("Account[0]: "+App.accounts[0]);
          
          App.web3Provider = window.ethereum;
          console.log("modern dapp browser");
        }
        // Legacy dapp browsers...
        else if (window.web3) {
          App.web3Provider = window.web3.currentProvider;
          App.accounts = window.eth.accounts;
          console.log("legacy dapp browser");
        }
        // if no injected web3 instance is detected, fall back to Ganache
        else {
          App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
        }
        
        //web3 = new Web3(App.web3Provider);
    
        return App.initContract();
        
      },
    
      initContract: function() {
    
        $.getJSON('Adoption.json', function(data) {
          // Get the necessary contract artifact file and instantiate it with @truffle/contract
          var AdoptionArtifact = data;
          try { App.contracts.Adoption = TruffleContract(AdoptionArtifact); } catch (error) { console.error(error); }
    
          // Set the provider for our contract
          try {
            App.contracts.Adoption.setProvider(App.web3Provider);
          } catch (error){
            console.log(error);
          }
          // Use our contract to retrieve and mark the adopted pets
          return App.markAdopted();
        });
    
        return App.bindEvents();
      },
    
      bindEvents: function() {
        $(document).on('click', '.btn-adopt', App.handleAdopt);
        $(document).on('click', '.btn-return', App.handleReturn);
      },
    
      markAdopted: function() {
    
        var adoptionInstance;
        App.contracts.Adoption.deployed().then(function(instance) {
          adoptionInstance = instance;
    
          return adoptionInstance.getAdopters.call();
        }).then(function(adopters) {
            
            for(i=0;i<adopters.length;i++){
                if (adopters[i] != '0x0000000000000000000000000000000000000000') {
                    if (adopters[i] == App.accounts[0]){
                        $('.panel-pet').eq(i).find('.btn-return').text('Return').attr('disabled', false);
                        $('.panel-pet').eq(i).find('.btn-adopt').text('Adopted').attr('disabled', true);
                    } else {
                        $('.panel-pet').eq(i).find('.btn-return').text('-').attr('disabled', true);
                        $('.panel-pet').eq(i).find('.btn-adopt').text('Adopted').attr('disabled', true);
                    }
                } else {
                    $('.panel-pet').eq(i).find('.btn-return').text('-').attr('disabled', true);
                }
            }
    
            
        }).catch(function(err) {
          console.log(err.message);
        });
      },
    
      handleReturn: function(event) {
        event.preventDefault();
        
        var petId = parseInt($(event.target).data('id'));
        
        console.log("handleReturn petId: "+petId+" Account[0]: "+App.accounts[0]);
        console.log("petID:"+petId);
        console.log("Account[0]: "+App.accounts[0]);
        
        var adoptionInstance;
        App.contracts.Adoption.deployed().then(function(instance) {
          adoptionInstance = instance;
    
          return adoptionInstance.returnPet(petId, {from: App.accounts[0]});
        }).then(function(result){
            App.markAdopted();
        });
        
      },
    
    
      handleAdopt: function(event) {
        event.preventDefault();
    
        var petId = parseInt($(event.target).data('id'));
        console.log("handleAdopt petId: "+petId+" Account[0]: "+App.accounts[0]);
        console.log("petId:"+petId);
    
        var adoptionInstance;
        App.contracts.Adoption.deployed().then(function(instance) {
          adoptionInstance = instance;
    
          return adoptionInstance.adopt(petId, {from: App.accounts[0]});
        }).then(function(result){
            App.markAdopted();
        });
        
      }
    
    };
    
    $(function() {
      $(window).load(function() {
        App.init();
      });
    });
    

    Adoption.sol

    pragma solidity ^0.5.0;
    
    contract Adoption {
        address[16] public adopters;
    
        // Adopting a pet
        function adopt(uint petId) public returns (uint) {
            require(petId >= 0 && petId <= 15);
    
            adopters[petId] = msg.sender;
    
            return petId;
        }
    
        // Retrieving the adopters
        function getAdopters() public view returns (address[16] memory) {
            return adopters;
        }
        
        // Return Pet
        function returnPet(uint petId) public returns (uint) {
            require(petId >= 0 && petId <= 15);
            
            // Address must own the pet
            require(msg.sender == adopters[petId]);
            
            // Clear the adopter for this pet
            adopters[petId] = address(0);
            
            return petId;
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-13
      • 2022-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多