Solidity
如何將大量數據填充到struct的映射中
我正在開發一款進入 Solidity 的遊戲,我希望能夠將元數據填充到我的智能合約中,以便能夠直接從遊戲功能中訪問它們。
所以我有一個基本的 ERC721 開始:
pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract GameEngine is ERC721Enumerable, Ownable { string baseURI; uint256 public maxSupply = 10000; bool isPopulated = false; struct Character { uint8 race; uint8 strength; uint8 agility; uint8 hp; uint8 xp; /*..*/ } mapping(uint => Character) characters; constructor( string memory _initBaseURI ) ERC721("GameCharacters", "GC") { _baseURI = _initBaseURI; } /* All basic functions for ERC721: mint, tokenURI, ...*/ }
現在……我希望能夠預先填充
characters
映射中的所有字元結構。我可以實現兩種方式:添加單個的功能
問題:但我必須呼叫它 10.000 次(或更多)!而且費用會很高。。
function populateOne(uint8 race, uint8 strength, uint8 agility, uint8 hp, /*...*/ ) external onlyOwner { require(!isPopulated, "Already Populated"); characters[characters.length] = Character(race, strength, agility, hp, 0, /*...*/ ); } function setPopulated() external onlyOwner { isPopulated = true; }
多合一功能
問題:不確定我能否使用 10,20 或 50 個 10k、20k 或 100k 項的數組呼叫此函式。
// All array must be the same size (maxSupply) function populateAll(uint8[] races, uint8[] strengths, uint8[] agilities, uint8[] hps, /*...*/ ) external onlyOwner { require(!isPopulated, "Already Populated"); for (uint256 i = 0; i < type.length; i++) { characters[i] = Character(races[i], strengths[i], agilities[i], hps[i], 0, /*...*/ ); } isPopulated = true; }
我錯過了什麼 ?有什麼解決辦法呢?感謝您的幫助,文章,程式碼,..我正在接受一切:p
您對這兩種解決方案的理解都是正確的。有幾件事情需要考慮。
解決方案 1
這很容易實現,但正如您所提到的,您將為每筆交易支付汽油費。您可以使用multicall將多個呼叫批處理到單個事務中,但對於大量呼叫來說會非常昂貴。
解決方案 2
這是有道理的,但不可能提供任意大的數據作為輸入。雖然EIP-1985規定
calldata
最大大小約為 4GB,但您會更早地達到塊氣體限制。解決方案 3
您可以實施解決方案 2,但採用批處理格式。假設您決定批量大小為 100,您添加了前 100 個令牌的元數據。在下一次呼叫中,您添加下一個 100。您可以根據每個批次的氣體使用量來決定批次大小。這樣,您可以將呼叫次數減少到最低限度,同時保持在氣體限制以下。