Truffle

為什麼我的智能合約 rinkeby 交易失敗?

  • January 19, 2022

我在rinkeby網路中部署了智能合約,部署合約沒有問題。但是當我嘗試執行方法 addClient() 它總是失敗(似乎是氣體問題)。我嘗試使用 metamask 將 gas 價格更改為 2-3 醚,但仍然失敗。

https://rinkeby.etherscan.io/tx/0xd91fdbbf350511591685fcfd37d5d992a50c47f1eb36fc2200aca83d8f08cf2c

我的方法是不是太耗氣了?(我不這麼認為)

pragma solidity ^0.4.24;

/**
* @title Roles
* @dev Library for managing addresses assigned to a Role.
*/
library Roles {
 struct Role {
   mapping (address => bool) bearer;
 }

 /**
  * @dev give an account access to this role
  */
 function add(Role storage role, address account) internal {
   require(account != address(0));
   require(!has(role, account));

   role.bearer[account] = true;
 }

 /**
  * @dev remove an account's access to this role
  */
 function remove(Role storage role, address account) internal {
   require(account != address(0));
   require(has(role, account));
   role.bearer[account] = false;
 }

 /**
  * @dev check if an account has this role
  * @return bool
  */
 function has(Role storage role, address account)
   internal
   view
   returns (bool)
 {
   require(account != address(0));
   return role.bearer[account];
 }
}

在建構子級別有一個呼叫,將契約所有者添加為客戶端:

contract ClientRole {
 using Roles for Roles.Role;

 // Define 2 events, one for Adding, and other for Removing
 event ClientAdded(address indexed account);
 event ClientRemoved(address indexed account);

 // Define a struct 'clients' by inheriting from 'Roles' library, struct Role
 Roles.Role private clients;

 // In the constructor make the address that deploys this contract the 1st Client
 constructor() public {
   _addClient(msg.sender);
 }

 // Define a modifier that checks to see if msg.sender has the appropriate role
 modifier onlyClient() {
   require(isClient(msg.sender));
   _;
 }

 // Define a function 'isClient' to check this role
 function isClient(address account) public view returns (bool) {
   return clients.has(account);
 }

 // Define a function 'addClient' that adds this role
 function addClient(address account) public onlyClient {
   _addClient(account);
 }

 // Define a function 'removeClient' that adds this role
 function removeClient(address account) public onlyClient {
   _removeClient(account);
 }

 // Define a function 'renounceClient' to renounce this role
 function renounceClient() public {
   _removeClient(msg.sender);
 }

 // Define an internal function '_addClient' to add this role, called by 'addClient'
 function _addClient(address account) internal {
   clients.add(account);
   emit ClientAdded(account);
 }

 // Define an internal function '_removeClient' to remove this role, called by 'removeClient'
 function _removeClient(address account) internal {
   clients.remove(account);
   emit ClientRemoved(account);
 }
}

然後我使用一個名為 Verification.sol 的合約,而不是繼承 Client.sol 並addClient()從 Verification.sol 合約中呼叫該方法。

pragma solidity ^0.4.24;

import "../coffeeaccesscontrol/PeriRole.sol";
import "../coffeeaccesscontrol/ClientRole.sol";
import "../coffeecore/Ownable.sol";

// Define a contract 'verification'
contract Verification is ClientRole, PeriRole {

 // Define 'owner'
 address owner;

 // Define a variable with number of transaction
 uint  ct;

 // Define a public mapping 'items' that maps the ct to an Item.
 mapping (uint => Item) items;

 // Define a public mapping 'itemsHistory' that maps the ct to an array of TxHash, 
 // that track its journey through the verification -- to be sent from DApp.
 mapping (uint => string[]) itemsHistory;
 
 // Define enum 'State' with the following values:
 enum State 
 { 
   Rendez,  // 0
   PeriProcessed,  // 1
   ClientProcessed,  // 2
   bothPeri  // 3
 }

 State constant defaultState = State.Rendez;

 // Define enum 'VerifClient' with the following values:
 enum VeriClient 
 { 
   noShow,  // 0
   bad,  // 1
   good  // 2
 }

 // Define enum 'VeriPhotoPeri' with the following values:
 enum VeriPhotoPeri 
 { 
   noShow,  // 0
   bad,  // 1
   good  // 2
 }

 // Define enum 'VeriPeri' with the following values:
 enum VeriPeri
 { 
   noShow,  // 0
   bad,  // 1
   good  // 2
 }

 VeriClient constant defaultVeriClient = VeriClient.noShow;
 VeriPhotoPeri constant defaultVeriPhotoPeri = VeriPhotoPeri.noShow;
 VeriPeri constant defaultVeriPeri = VeriPeri.noShow;

 // Define a struct 'Item' with the following fields:
 struct Item {
   uint    ct; // number of verifications in the blockchain
   address ownerID;  // Metamask-Ethereum address of the current owner as the product moves through 8 stages
   address clientID; // Metamask-Ethereum address of the client
   address    periID;  // Metamask-Ethereum address of the peripateticienne
   uint    dateRdv;  // date in digits
   State   itemState;  // Product State as represented in the enum above
   VeriClient itemVeriClient;
   VeriPhotoPeri itemVeriPhotoPeri;
   VeriPeri itemVeriPeri;
 }

(more methods -------------------------------------)
}

程式碼版本:

Truffle v5.4.24 (core: 5.4.24)
Solidity - 0.4.24 (solc-js)
Node v12.0.0
Web3.js v1.5.3

松露-config.js

rinkeby: {
 provider: () => new HDWalletProvider(mnemonic, `https://rinkeby.infura.io/v3/${infuraKey}`),
   network_id: 4,       // rinkeby's id
   gas: 4500000,      // 4500000  // rinkeby has a lower block limit than mainnet
   gasPrice: 10000000000, // 10000000000 
   from: publicAddress // contract owner in rinkeby: 0x08c1fa540e53c998B5572dA9dd9785f4Ff052704
},

謝謝你的幫助 !

契約是正確的,只是你沒有考慮到的一個小細節。回顧一下,

  1. 您正在從該地址部署合約0x..C9E3,因此將其作為客戶端列入白名單
  2. 您正在嘗試0x..C9E3通過呼叫 addClient 再次加入白名單

假設您使用的是這個Roles.sol庫的一個版本,如果我們查看它的實現,add我們會注意到兩個檢查:

 require(account != address(0)); // is my address valid
 require(!has(role, account)); // is my account new, no client role yet

0x..C9E3由於不滿足第二個條件,您正在執行的第二個事務嘗試添加將失敗。

**解決方案:**嘗試使用另一個地址添加另一個客戶端。應該工作正常!

PS 添加更多詳細資訊時,請編輯您的初始文章以使其井井有條。另外,請嘗試查看更新的 openzeppelin 訪問控制庫,總是能跟上最新的。

錯誤交易範例 | 請addClient使用另一個地址作為參數呼叫以使其工作。

在此處輸入圖像描述

引用自:https://ethereum.stackexchange.com/questions/119178