7

Gas Efficient Card Drawing in Solidity

 2 years ago
source link: https://medium.com/taipei-ethereum-meetup/gas-efficient-card-drawing-in-solidity-af49bb135a08
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Gas Efficient Card Drawing in Solidity

Assign random numbers as the index of newly minted NFTs

Scenario

The fun of generative art NFT projects depends on randomness. The industry standard is “blind box”, where both the images’ serial number and the NFTs’ index are predetermined but will be shifted randomly when the selling period ends. (They call it “reveal”) This approach effectively solves the randomness issue. However, it also requires buyers to wait until the campaign terminates. What if buyers want to know the exact card right away? We’ll need a reliable onchain card drawing solution.

The creator of Astrogator🐊 isn’t a fan of blind boxes; instead, it thinks unpacking cards right after purchase is more interesting.

When initializing this NFT contract, the creator will determine the total supply of it. And there will be an iterable function that is randomly picking a number from the remaining pool. The number must be in range and must not collide with any existing ones.

Our top priority is accessibility/gas efficiency. Given that gas cost on Ethereum is damn high nowadays, we need an elegant algorithm to control gas expanse at an acceptable range.

Achieving robust randomness isn’t the primary goal here. We assume there’s no strong financial incentive to cheat, so the RNG isn’t specified. Implementers can bring their own source of randomness that they think is good enough.

Implementation

Overview

The implementation is pretty short and straightforward. Imagine there’s an array that contains all remaining(unsold) cards. When drawIndex() is called, it generates a (uniform) random seed to draw a card from the array, shortens the array, and returns the selected card.

Algorithm

Drawing X cards from a deck with the same X amount of cards is equal to shuffling the deck and dealing them sequentially. It’s not a surprise that our algorithm is similar to random shuffling, and the only difference is turning that classic algo into an interactive version.

A typical random shuffle looks like this: for an array with N elements, you randomly pick a number i in (0,N), swap array[0] and array[i], then choose another number i in (1,N), swap array[1] and array[i], and so on. Eventually, you’ll get a mathematically random array in O(N) time.

So, the concept of our random card dealing is the same. When a user mints a new card, the smart contract picks a number in the array as NFT index, then grabs a number from the tail to fill the vacancy, in order to keep the array continuous.

Tweak

Furthermore, as long as the space of the NFT index is known, we don’t need to declare/initialize an array(which is super gas-intensive). Instead, assume there’s such an array that the n-th element is n, we don’t actually initialize it (so it is an array only contains “0”) until the rule is broken.

For the convenience of explanation, let’s call that mapping cache. If cache[i] is empty, it should be interpreted as i instead of 0. On the other hand, when a number is chosen and used, we’ll need to fill it up with another unused number. An intuitive method is to pick a number from the end of the array, since the length of the array is going to decrease by 1.

By doing so, the gas cost in the worst-case scenario is bound to be constant.

Performance and limitation

Comparing with the normal ascending index NFT minting, our random NFT implementation requires two extra SSTORE and one extra SLOAD, which cost 12600 ~ 27600 (5000+20000+2600) excess gas per token minted.

Theoretically, any instantly generated onchain random number is vulnerable. We can restrict contract interaction to mitigate risk. The mitigation is far from perfect, but it is the tradeoff that we have to accept.

1*N4qBNh5I2PnL5DJO6r4eIw.png?q=20
gas-efficient-card-drawing-in-solidity-af49bb135a08

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK