Truffle
為什麼我的智能合約 rinkeby 交易失敗?
我在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 },
謝謝你的幫助 !
契約是正確的,只是你沒有考慮到的一個小細節。回顧一下,
- 您正在從該地址部署合約
0x..C9E3
,因此將其作為客戶端列入白名單- 您正在嘗試
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
使用另一個地址作為參數呼叫以使其工作。