diff --git a/python/tests/bench.py b/python/tests/bench.py new file mode 100644 index 0000000..edddd86 --- /dev/null +++ b/python/tests/bench.py @@ -0,0 +1,72 @@ +# standard imports +import os +import unittest +import json +import logging + +# third-party imports +import web3 +import eth_tester +import eth_abi + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +logging.getLogger('web3').setLevel(logging.WARNING) +logging.getLogger('eth.vm').setLevel(logging.WARNING) + +testdir = os.path.dirname(__file__) + +TAX_LEVEL = 10000 * 2 # 2% + + +class Test(unittest.TestCase): + + contract = None + + def setUp(self): + eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({ + 'gas_limit': 9000000, + }) + + f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.bin'), 'r') + self.bytecode = f.read() + f.close() + + f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.json'), 'r') + self.abi = json.load(f) + f.close() + + backend = eth_tester.PyEVMBackend(eth_params) + self.eth_tester = eth_tester.EthereumTester(backend) + provider = web3.Web3.EthereumTesterProvider(self.eth_tester) + self.w3 = web3.Web3(provider) + self.sink_address = self.w3.eth.accounts[9] + + def tearDown(self): + pass + + + def test_gas_changeperiod(self): + period = 43200 + for i in range(5): + c = self.w3.eth.contract(abi=self.abi, bytecode=self.bytecode) + tx_hash = c.constructor('Foo Token', 'FOO', 6, TAX_LEVEL * (10 ** 32), period, self.sink_address).transact({'from': self.w3.eth.accounts[0]}) + r = self.w3.eth.getTransactionReceipt(tx_hash) + contract = self.w3.eth.contract(abi=self.abi, address=r.contractAddress) + + start_block = self.w3.eth.blockNumber + b = self.w3.eth.getBlock(start_block) + start_time = b['timestamp'] + + period_seconds = period * 60 + self.eth_tester.time_travel(start_time + period_seconds + (60 * (10 ** i))) + tx_hash = contract.functions.changePeriod().transact() + r = self.w3.eth.getTransactionReceipt(tx_hash) + + print('{} ({}): {}'.format(i, 60 * (10 ** i), r['gasUsed'])) + +if __name__ == '__main__': + unittest.main() + + diff --git a/solidity/RedistributedDemurrageToken.sol b/solidity/RedistributedDemurrageToken.sol index cf01d56..c57f43b 100644 --- a/solidity/RedistributedDemurrageToken.sol +++ b/solidity/RedistributedDemurrageToken.sol @@ -30,7 +30,7 @@ contract RedistributedDemurrageToken { event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value); - //event Debug(uint256 _foo); + event Debug(bytes32 _foo); event Decayed(uint256 indexed _period, uint256 indexed _periodCount, uint256 indexed _oldAmount, uint256 _newAmount); event Redistribution(address indexed _account, uint256 indexed _period, uint256 _value); @@ -72,7 +72,7 @@ contract RedistributedDemurrageToken { periodCount = actualPeriod() - toDemurragePeriod(demurrageModifier); - currentDemurrageAmount = toTaxPeriodAmount(anchorDemurrageAmount, periodCount); + currentDemurrageAmount = decayBy(anchorDemurrageAmount, periodCount); return (baseBalance * currentDemurrageAmount) / (ppmDivider * 1000000); } @@ -137,7 +137,6 @@ contract RedistributedDemurrageToken { require(minter[msg.sender]); - applyDemurrage(); changePeriod(); baseAmount = _amount; totalSupply += _amount; @@ -197,6 +196,8 @@ contract RedistributedDemurrageToken { tmpRedistribution |= (participants & 0x0fffffffff) << 104; redistributions[redistributions.length-1] = bytes32(tmpRedistribution); + + return true; } // Save the current total supply amount to the current redistribution period @@ -208,6 +209,7 @@ contract RedistributedDemurrageToken { currentRedistribution |= totalSupply << 32; redistributions[redistributions.length-1] = bytes32(currentRedistribution); + return true; } // Get the demurrage period of the current block number @@ -240,6 +242,7 @@ contract RedistributedDemurrageToken { account[_account] &= 0xffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff; account[_account] |= bytes32(_period << 72); incrementRedistributionParticipants(); + return true; } // Determine whether the unit number is rounded down, rounded up or evenly divides. @@ -274,9 +277,7 @@ contract RedistributedDemurrageToken { if (truncatedResult < redistributionSupply) { redistributionPeriod = toRedistributionPeriod(_redistribution); // since we reuse period here, can possibly be optimized by passing period instead - //redistributions[redistributionPeriod-1] &= 0x0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff; // just to be safe, zero out all participant count data, in this case there will be only one redistributions[redistributionPeriod-1] &= 0xfffffffffffffffffffffffffffff000000000ffffffffffffffffffffffffff; // just to be safe, zero out all participant count data, in this case there will be only one - //redistributions[redistributionPeriod-1] |= 0x8000000001000000000000000000000000000000000000000000000000000000; redistributions[redistributionPeriod-1] |= 0x8000000000000000000000000000000000000100000000000000000000000000; } @@ -323,7 +324,7 @@ contract RedistributedDemurrageToken { return false; } lastDemurrageAmount = toDemurrageAmount(demurrageModifier); - newDemurrageAmount = toTaxPeriodAmount(lastDemurrageAmount, periodCount); + newDemurrageAmount = decayBy(lastDemurrageAmount, periodCount); demurrageModifier = 0; demurrageModifier |= (newDemurrageAmount & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff); demurrageModifier |= (epochPeriodCount << 128); @@ -350,7 +351,8 @@ contract RedistributedDemurrageToken { uint256 currentPeriod; uint256 currentParticipants; uint256 currentRemainder; - uint256 currentRedistributionDemurrage; + uint256 currentDemurrageAmount; + uint256 nextRedistributionDemurrage; uint256 demurrageCounts; uint256 periodTimestamp; @@ -358,12 +360,22 @@ contract RedistributedDemurrageToken { if (currentRedistribution == bytes32(0x00)) { return false; } - periodTimestamp = getPeriodTimeDelta(currentPeriod); - demurrageCounts = demurrageCycles(periodTimestamp); - currentRedistributionDemurrage = toRedistributionDemurrageModifier(currentRedistribution); - + currentPeriod = toRedistributionPeriod(currentRedistribution); - nextRedistribution = toRedistribution(0, toTaxPeriodAmount(currentRedistributionDemurrage, demurrageCounts), totalSupply, currentPeriod + 1); + periodTimestamp = getPeriodTimeDelta(currentPeriod); + + applyDemurrage(); + currentDemurrageAmount = toDemurrageAmount(demurrageModifier); + + demurrageCounts = demurrageCycles(periodTimestamp); + if (demurrageCounts > 0) { + nextRedistributionDemurrage = growBy(currentDemurrageAmount, demurrageCounts) / ppmDivider; + } else { + nextRedistributionDemurrage = currentDemurrageAmount / ppmDivider; + } + + nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, currentPeriod + 1); + emit Debug(bytes32(currentDemurrageAmount)); redistributions.push(nextRedistribution); currentParticipants = toRedistributionParticipants(currentRedistribution); @@ -376,9 +388,23 @@ contract RedistributedDemurrageToken { return true; } + function growBy(uint256 _value, uint256 _period) public view returns (uint256) { + uint256 valueFactor; + uint256 truncatedTaxLevel; + + // TODO: if can't get to work, reverse the iteration from current period. + valueFactor = 1000000; + truncatedTaxLevel = taxLevel / ppmDivider; + + for (uint256 i = 0; i < _period; i++) { + valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / 1000000); + } + return (valueFactor * _value) / 1000000; + } + // Calculate a value reduced by demurrage by the given period // TODO: higher precision - function toTaxPeriodAmount(uint256 _value, uint256 _period) public view returns (uint256) { + function decayBy(uint256 _value, uint256 _period) public view returns (uint256) { uint256 valueFactor; uint256 truncatedTaxLevel; @@ -414,7 +440,7 @@ contract RedistributedDemurrageToken { supply = toRedistributionSupply(periodRedistribution); baseValue = ((supply / participants) * (taxLevel / 1000000)) / ppmDivider; - value = toTaxPeriodAmount(baseValue, period - 1); + value = decayBy(baseValue, period - 1); //account[_account] &= bytes32(0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff); account[_account] &= bytes32(0xffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff); @@ -433,7 +459,6 @@ contract RedistributedDemurrageToken { function approve(address _spender, uint256 _value) public returns (bool) { uint256 baseValue; - applyDemurrage(); changePeriod(); applyRedistributionOnAccount(msg.sender); @@ -448,7 +473,6 @@ contract RedistributedDemurrageToken { uint256 baseValue; bool result; - applyDemurrage(); changePeriod(); applyRedistributionOnAccount(msg.sender); @@ -465,7 +489,6 @@ contract RedistributedDemurrageToken { uint256 baseValue; bool result; - applyDemurrage(); changePeriod(); applyRedistributionOnAccount(msg.sender);