Last active
June 6, 2017 09:17
-
-
Save szerintedmi/ff6e60dbc411c055e59d4efa0b222bb5 to your computer and use it in GitHub Desktop.
Testing gas consumption with iterable maps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.8; | |
import "github.com/szerintedmi/solidity-itMapsLib/itMapsLib.sol"; | |
contract GasTest { | |
using itMaps for itMaps.itMapUintUint; | |
using itMaps for itMaps.itMapUintAddress; | |
using itMaps for itMaps.itMapAddressUint; | |
using itMaps for itMaps.itMapUintBool; | |
using GasTestLib for GasTestLib.Game; | |
GasTestLib.Game game; | |
function addBet(uint number) returns (bool overwrittenBet) { | |
if (game.winningAddress != address(0)) { | |
// it's a first bet so clear winner from previous round | |
game.winningAddress = address(0); | |
game.smallestNumber = 0; | |
} | |
return game.im_bets.insert(msg.sender,number); | |
} | |
function updateResults() returns (uint numberOfUnrevealedOrInvalidBets) { | |
return game._updateResults(); | |
} | |
function getResults() constant returns (address winningAddress, uint smallestNumber) { | |
return (game.winningAddress, game.smallestNumber); | |
} | |
} | |
library GasTestLib { | |
/* TODO: hove to structrure this? what data/logic shall we move here? */ | |
using itMaps for itMaps.itMapAddressUint; | |
using itMaps for itMaps.itMapUintAddress; | |
using itMaps for itMaps.itMapUintBool; | |
struct Game { | |
// playeraddress => bet number , bet number is 0 until revealed | |
itMaps.itMapAddressUint im_bets; | |
// callback queryId => player address : used for retrieving playerAddress at __callback | |
uint smallestNumber; | |
address winningAddress; | |
ResultCalcHelper resultCalcHelper; | |
} | |
struct ResultCalcHelper { | |
/* temporary structure to calculate results - can't be in memory because can't create mappings and dynamic arrays in memory | |
could it be done without storage ?? */ | |
itMaps.itMapUintAddress im_seenOnce; // Key:betnumber -> Value:PlayerAddress | |
itMaps.itMapUintBool im_seenMultiple; // Key:betnumber => Value:seen (bool) | |
// mapping(uint=>bool) m_seenMultiple; would be enough to calc results | |
// but it needs to be itmap to be able to destroy after round. | |
} | |
function _updateResults(Game storage self) internal returns (uint numberOfUnrevealedOrInvalidBets) { | |
// This function needs to be updated to run in batches of bets to allow | |
// higher number of bets evaluated without hitting the gas limit | |
ResultCalcHelper storage _resultCalcHelper = self.resultCalcHelper; | |
uint numberOfBets = self.im_bets.size() ; | |
uint numberToCheck; | |
// collect unique betnumbers in seenOnce from all bets (im_bets) | |
for(uint i = 0; i < numberOfBets ; i++) { | |
numberToCheck = self.im_bets.getValueByIndex(i); // CHECK: does it overwrite value in im_bets? | |
if(numberToCheck > 0) { // if this bid has been already revealed and valid... | |
if (_resultCalcHelper.im_seenMultiple.contains(numberToCheck) ) { | |
continue; | |
} | |
if (_resultCalcHelper.im_seenOnce.contains(numberToCheck)) { | |
_resultCalcHelper.im_seenOnce.remove(numberToCheck); | |
_resultCalcHelper.im_seenMultiple.insert(numberToCheck, true); | |
} else { | |
// first occurence, add to seenOnce | |
_resultCalcHelper.im_seenOnce.insert( numberToCheck, self.im_bets.getKeyByIndex(i)); | |
} | |
} else { | |
numberOfUnrevealedOrInvalidBets++ ; | |
} // numberToCheck | |
} // for | |
// find smallestNumber in seenOnce | |
self.winningAddress = address(0); | |
self.smallestNumber = 0; | |
uint seenOnceCount = _resultCalcHelper.im_seenOnce.size(); | |
for( i=0; i < seenOnceCount; i++) { | |
numberToCheck = _resultCalcHelper.im_seenOnce.getKeyByIndex(i); | |
if (numberToCheck < self.smallestNumber || self.smallestNumber == 0) { | |
self.smallestNumber = numberToCheck; | |
self.winningAddress = _resultCalcHelper.im_seenOnce.getValueByIndex(i); | |
} | |
} | |
// Clean up | |
// CHECK: is it the best way? ie. shall we just set array lengthto zero? (im_seenOnce.clear()) | |
// https://ethereum.stackexchange.com/questions/14017/solidity-how-could-i-apply-delete-to-complete-storage-ref-with-one-call | |
_resultCalcHelper.im_seenOnce.destroy(); | |
_resultCalcHelper.im_seenMultiple.destroy(); | |
self.im_bets.destroy(); | |
return numberOfUnrevealedOrInvalidBets; | |
} // updateResults | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment