Anish-Agnihotri / MultiRaffle

NFT distribution with (1) randomized, multi-winner raffles and (2) bulk on-chain metadata generation.
GNU Affero General Public License v3.0
269 stars 52 forks source link

shuffling costs #10

Open brossetti1 opened 3 years ago

brossetti1 commented 3 years ago

here are the reported gas numbers from the dapp-tools test suite if you run the specs around this method:

Running 5 tests for src/test/Benchmark.t.sol:MultiRaffleBenchmark
[PASS] testShuffleOneThousand() (gas: 231041478)
[PASS] testShuffleTen() (gas: 228839717)
[PASS] testShuffleHundred() (gas: 229039899)
[PASS] testShuffleTwenty() (gas: 228861935)
[PASS] testShuffleTenThousand() (gas: 251057487)

when i do the calculation of 10 shuffles vs 10,000 shuffles based on the approximate gas costs:

// total = gas for shuffle * current gwie cost
// gas low - 111 gwie -> 0.00000011 eth
// gas medium - 120 gwie -> 0.00000012 eth
// gas high - 140 gwie ->  0.00000014 eth

// shuffle 10 times
> 231041478 * 0.00000011
=> 25.414562580000002 eth
> 231041478 * 0.00000012
=> 27.724977359999997 eth
> 231041478 * 0.00000014
=> 32.3458069 eth

// shuffle 10000 times
> 251057487 * 0.00000011
=> 27.616323570000002 eth
> 251057487 * 0.00000012
=> 30.126898439999998 eth
> 251057487 * 0.00000014
=> 35.14804818 eth

I have a few questions around the shuffle according to these example calculations, assuming they are correct:

1) the costs are high, shuffling 10000 times though is only approximately 2-3 ether more than shuffling 10 times - why is this cost so close considering shuffle count in total is drastically different?

2) I understand the paradigm blog post and this repo come with no guarantees that this style of contract could be run on L1, I assume its mainly because of the shuffle costs - is there a way that anyone can think of to provably run the shuffle offchain and only write the final state of the shuffle back on chain?

I was thinking a merkle proof potentially but im unsure of the exact correct steps to prove-ably run the shuffle off chain so I was hoping someone might be able to provide guidance on what that might look like if you can go that route.

3) if the shuffling cannot be done offchain in a provable and appropriate fashion - is there a randomish enough shuffle implementation that would be more cost efficient or not so heavy -- that could be implemented in the place of the Fisher-Yates shuffle?

one piece im looking at is this requirement:

// Ensure raffle requires clearing (entries !< supply)
require(raffleEntries.length > AVAILABLE_SUPPLY, "Raffle does not need clearing");
// Ensure raffle requires clearing (already cleared)
require(shuffledCount != AVAILABLE_SUPPLY, "Raffle has already been cleared");

if AVAILABLE_SUPPLY = 10000: if raffleEntries.length == 9999 then no shuffling is required if raffleEntries.length == 10001 then 10000 shuffles are required if raffleEntries.length == 10500 then 10000 shuffles are required etc

this boundary of all or nothing seems like it could be reduced if you wanted to ratchet down the intensity of making an exact shuffle - potentially an adjusting threshold in which fluctuates iterations based on AVAILABLE_SUPPLY + AVAILABLE_SUPPLY > raffleEntries.length > AVAILABLE_SUPPLY if that makes sense.. the Fisher-Yates shuffle seems like it requires the entire supply to be shuffled in order to truly create randomness, wondering if there is an in between alternative shuffle that would still be somewhat respectable level of randomness.. thoughts?