def __init__(self): tester.GASPRICE = 0 tester.STARTGAS = long(6.7 * 10**7) config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001 config_metropolis['GENESIS_GAS_LIMIT'] = 2**60 config_metropolis['MIN_GAS_LIMIT'] = 2**60 config_metropolis['BLOCK_GAS_LIMIT'] = 2**60 for a in range(10): tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24} self.chain = Chain(env=Env(config=config_metropolis)) self.contracts = {} self.testerAddress = self.generateTesterMap('a') self.testerKey = self.generateTesterMap('k') self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values())) if path.isfile('./allFiredEvents'): remove_file('./allFiredEvents') self.relativeContractsPath = '../source/contracts' self.relativeTestContractsPath = 'solidity_test_helpers' self.externalContractsPath = '../source/contracts/external' self.coverageMode = pytest.config.option.cover self.subFork = pytest.config.option.subFork if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.relativeContractsPath = '../coverageEnv/contracts' self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers' self.externalContractsPath = '../coverageEnv/contracts/external'
def resetToSnapshot(self, snapshot): if not 'state' in snapshot: raise "snapshot is missing 'state'" if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'" self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis)) self.contracts = {} for contractName in snapshot['contracts']: contract = snapshot['contracts'][contractName] self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])
def resetToSnapshot(self, snapshot): if not 'state' in snapshot: raise "snapshot is missing 'state'" if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'" self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis)) if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.contracts = {} for contractName in snapshot['contracts']: contract = snapshot['contracts'][contractName] self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])
def __init__(self): tester.GASPRICE = 0 config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001 config_metropolis['GENESIS_GAS_LIMIT'] = 2**60 config_metropolis['MIN_GAS_LIMIT'] = 2**60 config_metropolis['BLOCK_GAS_LIMIT'] = 2**60 for a in range(10): tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24} self.chain = Chain(env=Env(config=config_metropolis)) self.contracts = {} self.testerAddress = self.generateTesterMap('a') self.testerKey = self.generateTesterMap('k')
def __init__(self): tester.GASPRICE = 0 tester.STARTGAS = long(6.7 * 10**7) config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001 config_metropolis['GENESIS_GAS_LIMIT'] = 2**60 config_metropolis['MIN_GAS_LIMIT'] = 2**60 config_metropolis['BLOCK_GAS_LIMIT'] = 2**60 for a in range(10): tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24} self.chain = Chain(env=Env(config=config_metropolis)) self.contracts = {} self.testerAddress = self.generateTesterMap('a') self.testerKey = self.generateTesterMap('k') self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values())) if path.isfile('./allFiredEvents'): remove_file('./allFiredEvents') self.relativeContractsPath = '../source/contracts' self.relativeTestContractsPath = 'solidity_test_helpers' self.coverageMode = pytest.config.option.cover if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.relativeContractsPath = '../coverageEnv/contracts' self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers'
def resetToSnapshot(self, snapshot): if not 'state' in snapshot: raise "snapshot is missing 'state'" if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'" self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis)) if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.contracts = {} for contractName in snapshot['contracts']: contract = snapshot['contracts'][contractName] self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])
def init_contracts(nodes): result = dict() tester_state = Chain() for address, contract in CONTRACTS.iteritems(): contract_path = path.join(CONTRACTS_DIR, contract['file']) simple_compiled = compile_file(contract_path) simple_data = solidity_get_contract_data( simple_compiled, contract_path, contract['name'], ) ct = ContractTranslator(simple_data['abi']) if (address == '0x00000000000000000000000000000000013241a3'): extra = (ct.encode_constructor_arguments([nodes[address]]) if nodes[address] else b'') else: extra = (ct.encode_constructor_arguments([nodes[address][0], nodes[address][1]]) if nodes[address] else b'') print(binascii.hexlify(simple_data['bin'] + extra)) abi_address = tester_state.contract(simple_data['bin'] + extra) tester_state.mine() account = tester_state.chain.state.account_to_dict(abi_address) result[address] = {'code': account['code'], 'storage': account['storage'], 'nonce': account['nonce']} return result
def test_abicontract_interface(): """ Test for issue #370. """ tester_state = Chain() contract_path = path.join(CONTRACTS_DIR, 'simple_contract.sol') contract_name = 'Simple' simple_compiled = compile_file(contract_path) simple_data = solidity_get_contract_data( simple_compiled, contract_path, contract_name, ) simple_address = tester_state.contract(simple_data['bin']) # ABIContract class must accept json_abi abi_json = json.dumps(simple_data['abi']).encode('utf-8') abi = ABIContract( _chain=tester_state, _abi=abi_json, address=simple_address, ) assert abi.test() == 1 # pylint: disable=no-member
class ContractsFixture: signatures = {} compiledCode = {} #### #### Static Methods #### @staticmethod def ensureCacheDirectoryExists(): if not path.exists(COMPILATION_CACHE): makedirs(COMPILATION_CACHE) def generateSignature(self, relativeFilePath): ContractsFixture.ensureCacheDirectoryExists() filename = path.basename(relativeFilePath) name = path.splitext(filename)[0] outputPath = path.join(COMPILATION_CACHE, name + 'Signature') lastCompilationTime = path.getmtime(outputPath) if path.isfile(outputPath) else 0 if path.getmtime(relativeFilePath) > lastCompilationTime: print('generating signature for ' + name) extension = path.splitext(filename)[1] signature = None if extension == '.sol': signature = self.compileSolidity(relativeFilePath)['abi'] else: raise with open(outputPath, mode='w') as file: json_dump(signature, file) else: pass#print('using cached signature for ' + name) with open(outputPath, 'r') as file: signature = json_load(file) return(signature) def getCompiledCode(self, relativeFilePath): filename = path.basename(relativeFilePath) name = path.splitext(filename)[0] if name in ContractsFixture.compiledCode: return ContractsFixture.compiledCode[name] dependencySet = set() self.getAllDependencies(relativeFilePath, dependencySet) ContractsFixture.ensureCacheDirectoryExists() compiledOutputPath = path.join(COMPILATION_CACHE, name) lastCompilationTime = path.getmtime(compiledOutputPath) if path.isfile(compiledOutputPath) else 0 needsRecompile = False for dependencyPath in dependencySet: if (path.getmtime(dependencyPath) > lastCompilationTime): needsRecompile = True break if (needsRecompile): print('compiling ' + name + '...') extension = path.splitext(filename)[1] compiledCode = None if extension == '.sol': compiledCode = bytearray.fromhex(self.compileSolidity(relativeFilePath)['evm']['bytecode']['object']) else: raise with io_open(compiledOutputPath, mode='wb') as file: file.write(compiledCode) else: pass#print('using cached compilation for ' + name) with io_open(compiledOutputPath, mode='rb') as file: compiledCode = file.read() contractSize = len(compiledCode) if (contractSize >= CONTRACT_SIZE_LIMIT): print('%sContract %s is OVER the size limit by %d bytes%s' % (bcolors.FAIL, name, contractSize - CONTRACT_SIZE_LIMIT, bcolors.ENDC)) elif (contractSize >= CONTRACT_SIZE_WARN_LEVEL): print('%sContract %s is under size limit by only %d bytes%s' % (bcolors.WARN, name, CONTRACT_SIZE_LIMIT - contractSize, bcolors.ENDC)) elif (contractSize > 0): pass#print('Size: %i' % contractSize) ContractsFixture.compiledCode[name] = compiledCode return(compiledCode) def compileSolidity(self, relativeFilePath): absoluteFilePath = resolveRelativePath(relativeFilePath) filename = path.basename(relativeFilePath) contractName = path.splitext(filename)[0] print absoluteFilePath compilerParameter = { 'language': 'Solidity', 'sources': { absoluteFilePath: { 'urls': [ absoluteFilePath ] } }, 'settings': { # TODO: Remove 'remappings' line below and update 'sources' line above 'remappings': [ '=%s/' % resolveRelativePath(self.relativeContractsPath), 'TEST=%s/' % resolveRelativePath(self.relativeTestContractsPath) ], 'optimizer': { 'enabled': True, 'runs': 200 }, 'outputSelection': { "*": { '*': [ 'metadata', 'evm.bytecode', 'evm.sourceMap', 'abi' ] } } } } return compile_standard(compilerParameter, allow_paths=resolveRelativePath("../"))['contracts'][absoluteFilePath][contractName] def getAllDependencies(self, filePath, knownDependencies): knownDependencies.add(filePath) fileDirectory = path.dirname(filePath) with open(filePath, 'r') as file: fileContents = file.read() matches = findall("inset\('(.*?)'\)", fileContents) for match in matches: dependencyPath = path.abspath(path.join(fileDirectory, match)) if not dependencyPath in knownDependencies: self.getAllDependencies(dependencyPath, knownDependencies) matches = findall("create\('(.*?)'\)", fileContents) for match in matches: dependencyPath = path.abspath(path.join(fileDirectory, match)) if not dependencyPath in knownDependencies: self.getAllDependencies(dependencyPath, knownDependencies) matches = findall("import ['\"](.*?)['\"]", fileContents) for match in matches: dependencyPath = path.join(BASE_PATH, self.relativeContractsPath, match) if "TEST" in dependencyPath: dependencyPath = path.join(BASE_PATH, self.relativeTestContractsPath, match).replace("TEST/", "") if not path.isfile(dependencyPath): raise Exception("Could not resolve dependency file path: %s" % dependencyPath) if not dependencyPath in knownDependencies: self.getAllDependencies(dependencyPath, knownDependencies) return(knownDependencies) #### #### Class Methods #### def __init__(self): tester.GASPRICE = 0 tester.STARTGAS = long(6.7 * 10**7) config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001 config_metropolis['GENESIS_GAS_LIMIT'] = 2**60 config_metropolis['MIN_GAS_LIMIT'] = 2**60 config_metropolis['BLOCK_GAS_LIMIT'] = 2**60 for a in range(10): tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24} self.chain = Chain(env=Env(config=config_metropolis)) self.contracts = {} self.testerAddress = self.generateTesterMap('a') self.testerKey = self.generateTesterMap('k') self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values())) if path.isfile('./allFiredEvents'): remove_file('./allFiredEvents') self.relativeContractsPath = '../source/contracts' self.relativeTestContractsPath = 'solidity_test_helpers' self.externalContractsPath = '../source/contracts/external' self.coverageMode = pytest.config.option.cover self.subFork = pytest.config.option.subFork if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.relativeContractsPath = '../coverageEnv/contracts' self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers' self.externalContractsPath = '../coverageEnv/contracts/external' def writeLogToFile(self, message): with open('./allFiredEvents', 'a') as logsFile: logsFile.write(json_dumps(message.to_dict()) + '\n') def distributeRep(self, universe): # Get the reputation token for this universe and migrate legacy REP to it reputationToken = self.applySignature('ReputationToken', universe.getReputationToken()) legacyRepToken = self.applySignature('LegacyReputationToken', reputationToken.getLegacyRepToken()) totalSupply = legacyRepToken.balanceOf(tester.a0) legacyRepToken.approve(reputationToken.address, totalSupply) reputationToken.migrateFromLegacyReputationToken() def generateTesterMap(self, ch): testers = {} for i in range(0,9): testers[i] = getattr(tester, ch + "%d" % i) return testers def uploadAndAddToAugur(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]): lookupKey = lookupKey if lookupKey else path.splitext(path.basename(relativeFilePath))[0] contract = self.upload(relativeFilePath, lookupKey, signatureKey, constructorArgs) if not contract: return None self.contracts['Augur'].registerContract(lookupKey.ljust(32, '\x00'), contract.address) return(contract) def generateAndStoreSignature(self, relativePath): key = path.splitext(path.basename(relativePath))[0] resolvedPath = resolveRelativePath(relativePath) if self.coverageMode: resolvedPath = resolvedPath.replace("tests", "coverageEnv").replace("source/", "coverageEnv/") if key not in ContractsFixture.signatures: ContractsFixture.signatures[key] = self.generateSignature(resolvedPath) def upload(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]): resolvedPath = resolveRelativePath(relativeFilePath) if self.coverageMode: resolvedPath = resolvedPath.replace("tests", "coverageEnv").replace("source/", "coverageEnv/") lookupKey = lookupKey if lookupKey else path.splitext(path.basename(resolvedPath))[0] signatureKey = signatureKey if signatureKey else lookupKey if lookupKey in self.contracts: return(self.contracts[lookupKey]) compiledCode = self.getCompiledCode(resolvedPath) # abstract contracts have a 0-length array for bytecode if len(compiledCode) == 0: if ("libraries" in relativeFilePath or lookupKey.startswith("I") or lookupKey.startswith("Base") or lookupKey.startswith("DS")): pass#print "Skipping upload of " + lookupKey + " because it had no bytecode (likely a abstract class/interface)." else: raise Exception("Contract: " + lookupKey + " has no bytecode, but this is not expected. It probably doesn't implement all its abstract methods") return None if signatureKey not in ContractsFixture.signatures: ContractsFixture.signatures[signatureKey] = self.generateSignature(resolvedPath) signature = ContractsFixture.signatures[signatureKey] contractTranslator = ContractTranslator(signature) if len(constructorArgs) > 0: compiledCode += contractTranslator.encode_constructor_arguments(constructorArgs) contractAddress = bytesToHexString(self.chain.contract(compiledCode, language='evm')) contract = ABIContract(self.chain, contractTranslator, contractAddress) self.contracts[lookupKey] = contract return(contract) def applySignature(self, signatureName, address): assert address if type(address) is long: address = longToHexString(address) translator = ContractTranslator(ContractsFixture.signatures[signatureName]) contract = ABIContract(self.chain, translator, address) return contract def createSnapshot(self): self.chain.tx(sender=tester.k0, to=tester.a1, value=0) self.chain.mine(1) contractsCopy = {} for contractName in self.contracts: contractsCopy[contractName] = dict(translator = self.contracts[contractName].translator, address = self.contracts[contractName].address) return { 'state': self.chain.head_state.to_snapshot(), 'contracts': contractsCopy } def resetToSnapshot(self, snapshot): if not 'state' in snapshot: raise "snapshot is missing 'state'" if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'" self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis)) if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.contracts = {} for contractName in snapshot['contracts']: contract = snapshot['contracts'][contractName] self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address']) #### #### Bulk Operations #### def uploadAllContracts(self): for directory, _, filenames in walk(resolveRelativePath(self.relativeContractsPath)): # skip the legacy reputation directory since it is unnecessary and we don't support uploads of contracts with constructors yet if 'legacy_reputation' in directory: continue if 'external' in directory: continue for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if name == 'augur': continue if name == 'Augur': continue if name == 'Orders': continue # In testing we use the TestOrders version which lets us call protected methods if name == 'Time': continue # In testing and development we swap the Time library for a ControlledTime version which lets us manage block timestamp if name == 'ReputationTokenFactory': continue # In testing and development we use the TestNetReputationTokenFactory which lets us faucet onlySignatures = ["ReputationToken", "TestNetReputationToken", "Universe"] if name in onlySignatures: self.generateAndStoreSignature(path.join(directory, filename)) elif name == "TimeControlled": self.uploadAndAddToAugur(path.join(directory, filename), lookupKey = "Time", signatureKey = "TimeControlled") elif name == "TestNetReputationTokenFactory": self.uploadAndAddToAugur(path.join(directory, filename), lookupKey = "ReputationTokenFactory", signatureKey = "TestNetReputationTokenFactory") elif name == "TestOrders": self.uploadAndAddToAugur(path.join(directory, filename), lookupKey = "Orders", signatureKey = "TestOrders") else: self.uploadAndAddToAugur(path.join(directory, filename)) def uploadAllMockContracts(self): for directory, _, filenames in walk(resolveRelativePath(self.relativeTestContractsPath)): for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if not name.startswith('Mock'): continue if 'Factory' in name: self.upload(path.join(directory, filename)) else: self.uploadAndAddToAugur(path.join(directory, filename)) def uploadExternalContracts(self): for directory, _, filenames in walk(resolveRelativePath(self.externalContractsPath)): for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue constructorArgs = [] self.upload(path.join(directory, filename), constructorArgs=constructorArgs) def initializeAllContracts(self): contractsToInitialize = ['CompleteSets','CreateOrder','FillOrder','CancelOrder','Trade','ClaimTradingProceeds','Orders','Time','Cash','LegacyReputationToken'] for contractName in contractsToInitialize: if getattr(self.contracts[contractName], "initializeERC820", None): self.contracts[contractName].initializeERC820(self.contracts['Augur'].address) elif getattr(self.contracts[contractName], "initialize", None): self.contracts[contractName].initialize(self.contracts['Augur'].address) else: raise "contract has no 'initialize' method on it." #### #### Helpers #### def getSeededCash(self): cash = self.contracts['Cash'] cash.depositEther(value = 1, sender = tester.k9) return cash def approveCentralAuthority(self): authority = self.contracts['Augur'] contractsToApprove = ['Cash'] testersGivingApproval = [getattr(tester, 'k%i' % x) for x in range(0,10)] for testerKey in testersGivingApproval: for contractName in contractsToApprove: self.contracts[contractName].approve(authority.address, 2**254, sender=testerKey) def uploadAugur(self): # We have to upload Augur first augur = self.upload("../source/contracts/Augur.sol") self.contracts['Augur'].registerContract("Augur".ljust(32, '\x00'), augur.address) return augur def uploadShareToken(self, augurAddress = None): augurAddress = augurAddress if augurAddress else self.contracts['Augur'].address self.ensureShareTokenDependencies() shareTokenFactory = self.contracts['ShareTokenFactory'] shareToken = shareTokenFactory.createShareToken(augurAddress) return self.applySignature('shareToken', shareToken) def createUniverse(self): universeAddress = self.contracts['Augur'].createGenesisUniverse() universe = self.applySignature('Universe', universeAddress) assert universe.getTypeName() == stringToBytes('Universe') return universe def getShareToken(self, market, outcome): shareTokenAddress = market.getShareToken(outcome) assert shareTokenAddress shareToken = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['ShareToken']), shareTokenAddress) return shareToken def getOrCreateChildUniverse(self, parentUniverse, market, payoutDistribution): assert payoutDistributionHash childUniverseAddress = parentUniverse.getOrCreateChildUniverse(payoutDistribution) assert childUniverseAddress childUniverse = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Universe']), childUniverseAddress) return childUniverse def createYesNoMarket(self, universe, endTime, feePerEthInWei, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo="", validityBond=0): marketCreationFee = validityBond or universe.getOrCacheMarketCreationCost() with BuyWithCash(self.contracts['Cash'], marketCreationFee, sender, "validity bond"): marketAddress = universe.createYesNoMarket(endTime, feePerEthInWei, designatedReporterAddress, topic, description, extraInfo, sender=sender) assert marketAddress market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createCategoricalMarket(self, universe, numOutcomes, endTime, feePerEthInWei, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo=""): marketCreationFee = universe.getOrCacheMarketCreationCost() outcomes = [" "] * numOutcomes with BuyWithCash(self.contracts['Cash'], marketCreationFee, sender, "validity bond"): marketAddress = universe.createCategoricalMarket(endTime, feePerEthInWei, designatedReporterAddress, outcomes, topic, description, extraInfo, sender=sender) assert marketAddress market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createScalarMarket(self, universe, endTime, feePerEthInWei, maxPrice, minPrice, numTicks, designatedReporterAddress, sender=tester.k0, description="description", extraInfo=""): marketCreationFee = universe.getOrCacheMarketCreationCost() with BuyWithCash(self.contracts['Cash'], marketCreationFee, sender, "validity bond"): marketAddress = universe.createScalarMarket(endTime, feePerEthInWei, designatedReporterAddress, minPrice, maxPrice, numTicks, "", description, extraInfo, sender=sender) assert marketAddress market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createReasonableYesNoMarket(self, universe, sender=tester.k0, topic="", description="description", extraInfo="", validityBond=0): return self.createYesNoMarket( universe = universe, endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()), feePerEthInWei = 10**16, designatedReporterAddress = tester.a0, sender = sender, topic= topic, description= description, extraInfo= extraInfo, validityBond= validityBond) def createReasonableCategoricalMarket(self, universe, numOutcomes, sender=tester.k0): return self.createCategoricalMarket( universe = universe, numOutcomes = numOutcomes, endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()), feePerEthInWei = 10**16, designatedReporterAddress = tester.a0, sender = sender) def createReasonableScalarMarket(self, universe, maxPrice, minPrice, numTicks, sender=tester.k0): return self.createScalarMarket( universe = universe, endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()), feePerEthInWei = 10**16, maxPrice= maxPrice, minPrice= minPrice, numTicks= numTicks, designatedReporterAddress = tester.a0, sender = sender)
class ContractsFixture: signatures = {} compiledCode = {} #### #### Static Methods #### @staticmethod def ensureCacheDirectoryExists(): if not path.exists(COMPILATION_CACHE): makedirs(COMPILATION_CACHE) def generateSignature(self, relativeFilePath): ContractsFixture.ensureCacheDirectoryExists() filename = path.basename(relativeFilePath) name = path.splitext(filename)[0] outputPath = path.join(COMPILATION_CACHE, name + 'Signature') lastCompilationTime = path.getmtime(outputPath) if path.isfile(outputPath) else 0 if path.getmtime(relativeFilePath) > lastCompilationTime: print('generating signature for ' + name) extension = path.splitext(filename)[1] signature = None if extension == '.sol': signature = self.compileSolidity(relativeFilePath)['abi'] else: raise with open(outputPath, mode='w') as file: json_dump(signature, file) else: pass#print('using cached signature for ' + name) with open(outputPath, 'r') as file: signature = json_load(file) return(signature) def getCompiledCode(self, relativeFilePath): filename = path.basename(relativeFilePath) name = path.splitext(filename)[0] if name in ContractsFixture.compiledCode: return ContractsFixture.compiledCode[name] dependencySet = set() self.getAllDependencies(relativeFilePath, dependencySet) ContractsFixture.ensureCacheDirectoryExists() compiledOutputPath = path.join(COMPILATION_CACHE, name) lastCompilationTime = path.getmtime(compiledOutputPath) if path.isfile(compiledOutputPath) else 0 needsRecompile = False for dependencyPath in dependencySet: if (path.getmtime(dependencyPath) > lastCompilationTime): needsRecompile = True break if (needsRecompile): print('compiling ' + name + '...') extension = path.splitext(filename)[1] compiledCode = None if extension == '.sol': compiledCode = bytearray.fromhex(self.compileSolidity(relativeFilePath)['evm']['bytecode']['object']) else: raise with io_open(compiledOutputPath, mode='wb') as file: file.write(compiledCode) else: pass#print('using cached compilation for ' + name) with io_open(compiledOutputPath, mode='rb') as file: compiledCode = file.read() contractSize = len(compiledCode) if (contractSize >= CONTRACT_SIZE_LIMIT): print('%sContract %s is OVER the size limit by %d bytes%s' % (bcolors.FAIL, name, contractSize - CONTRACT_SIZE_LIMIT, bcolors.ENDC)) elif (contractSize >= CONTRACT_SIZE_WARN_LEVEL): print('%sContract %s is under size limit by only %d bytes%s' % (bcolors.WARN, name, CONTRACT_SIZE_LIMIT - contractSize, bcolors.ENDC)) elif (contractSize > 0): pass#print('Size: %i' % contractSize) ContractsFixture.compiledCode[name] = compiledCode return(compiledCode) def compileSolidity(self, relativeFilePath): absoluteFilePath = resolveRelativePath(relativeFilePath) filename = path.basename(relativeFilePath) contractName = path.splitext(filename)[0] print absoluteFilePath compilerParameter = { 'language': 'Solidity', 'sources': { absoluteFilePath: { 'urls': [ absoluteFilePath ] } }, 'settings': { # TODO: Remove 'remappings' line below and update 'sources' line above 'remappings': [ '=%s/' % resolveRelativePath(self.relativeContractsPath), 'TEST=%s/' % resolveRelativePath(self.relativeTestContractsPath) ], 'optimizer': { 'enabled': True, 'runs': 500 }, 'outputSelection': { "*": { '*': [ 'metadata', 'evm.bytecode', 'evm.sourceMap', 'abi' ] } } } } return compile_standard(compilerParameter, allow_paths=resolveRelativePath("../"))['contracts'][absoluteFilePath][contractName] def getAllDependencies(self, filePath, knownDependencies): knownDependencies.add(filePath) fileDirectory = path.dirname(filePath) with open(filePath, 'r') as file: fileContents = file.read() matches = findall("inset\('(.*?)'\)", fileContents) for match in matches: dependencyPath = path.abspath(path.join(fileDirectory, match)) if not dependencyPath in knownDependencies: self.getAllDependencies(dependencyPath, knownDependencies) matches = findall("create\('(.*?)'\)", fileContents) for match in matches: dependencyPath = path.abspath(path.join(fileDirectory, match)) if not dependencyPath in knownDependencies: self.getAllDependencies(dependencyPath, knownDependencies) matches = findall("import ['\"](.*?)['\"]", fileContents) for match in matches: dependencyPath = path.join(BASE_PATH, self.relativeContractsPath, match) if "TEST" in dependencyPath: dependencyPath = path.join(BASE_PATH, self.relativeTestContractsPath, match).replace("TEST/", "") if not path.isfile(dependencyPath): raise Exception("Could not resolve dependency file path: %s" % dependencyPath) if not dependencyPath in knownDependencies: self.getAllDependencies(dependencyPath, knownDependencies) return(knownDependencies) #### #### Class Methods #### def __init__(self): tester.GASPRICE = 0 tester.STARTGAS = long(6.7 * 10**7) config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001 config_metropolis['GENESIS_GAS_LIMIT'] = 2**60 config_metropolis['MIN_GAS_LIMIT'] = 2**60 config_metropolis['BLOCK_GAS_LIMIT'] = 2**60 for a in range(10): tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24} self.chain = Chain(env=Env(config=config_metropolis)) self.contracts = {} self.testerAddress = self.generateTesterMap('a') self.testerKey = self.generateTesterMap('k') self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values())) if path.isfile('./allFiredEvents'): remove_file('./allFiredEvents') self.relativeContractsPath = '../source/contracts' self.relativeTestContractsPath = 'solidity_test_helpers' self.coverageMode = pytest.config.option.cover if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.relativeContractsPath = '../coverageEnv/contracts' self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers' def writeLogToFile(self, message): with open('./allFiredEvents', 'a') as logsFile: logsFile.write(json_dumps(message.to_dict()) + '\n') def distributeRep(self, universe): # Get the reputation token for this universe and migrate legacy REP to it reputationToken = self.applySignature('ReputationToken', universe.getReputationToken()) reputationToken.migrateBalancesFromLegacyRep([tester.a0]) def generateTesterMap(self, ch): testers = {} for i in range(0,9): testers[i] = getattr(tester, ch + "%d" % i) return testers def uploadAndAddToController(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]): lookupKey = lookupKey if lookupKey else path.splitext(path.basename(relativeFilePath))[0] contract = self.upload(relativeFilePath, lookupKey, signatureKey, constructorArgs) if not contract: return None self.contracts['Controller'].registerContract(lookupKey.ljust(32, '\x00'), contract.address, garbageBytes20, garbageBytes32) return(contract) def upload(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]): resolvedPath = resolveRelativePath(relativeFilePath) if self.coverageMode: resolvedPath = resolvedPath.replace("tests", "coverageEnv").replace("source/", "coverageEnv/") lookupKey = lookupKey if lookupKey else path.splitext(path.basename(resolvedPath))[0] signatureKey = signatureKey if signatureKey else lookupKey if lookupKey in self.contracts: return(self.contracts[lookupKey]) compiledCode = self.getCompiledCode(resolvedPath) # abstract contracts have a 0-length array for bytecode if len(compiledCode) == 0: if ("libraries" in relativeFilePath or lookupKey.startswith("I") or lookupKey.startswith("Base")): pass#print "Skipping upload of " + lookupKey + " because it had no bytecode (likely a abstract class/interface)." else: raise Exception("Contract: " + lookupKey + " has no bytecode, but this is not expected. It probably doesn't implement all its abstract methods") return None if signatureKey not in ContractsFixture.signatures: ContractsFixture.signatures[signatureKey] = self.generateSignature(resolvedPath) signature = ContractsFixture.signatures[signatureKey] contractTranslator = ContractTranslator(signature) if len(constructorArgs) > 0: compiledCode += contractTranslator.encode_constructor_arguments(constructorArgs) contractAddress = bytesToHexString(self.chain.contract(compiledCode, language='evm')) contract = ABIContract(self.chain, contractTranslator, contractAddress) self.contracts[lookupKey] = contract return(contract) def applySignature(self, signatureName, address): assert address if type(address) is long: address = longToHexString(address) translator = ContractTranslator(ContractsFixture.signatures[signatureName]) contract = ABIContract(self.chain, translator, address) return contract def createSnapshot(self): self.chain.tx(sender=tester.k0, to=tester.a1, value=0) self.chain.mine(1) contractsCopy = {} for contractName in self.contracts: contractsCopy[contractName] = dict(translator = self.contracts[contractName].translator, address = self.contracts[contractName].address) return { 'state': self.chain.head_state.to_snapshot(), 'contracts': contractsCopy } def resetToSnapshot(self, snapshot): if not 'state' in snapshot: raise "snapshot is missing 'state'" if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'" self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis)) if self.coverageMode: self.chain.head_state.log_listeners.append(self.writeLogToFile) self.contracts = {} for contractName in snapshot['contracts']: contract = snapshot['contracts'][contractName] self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address']) #### #### Bulk Operations #### def uploadAllContracts(self): for directory, _, filenames in walk(resolveRelativePath(self.relativeContractsPath)): # skip the legacy reputation directory since it is unnecessary and we don't support uploads of contracts with constructors yet if 'legacy_reputation' in directory: continue for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if name == 'controller': continue if name == 'Augur': continue if name == 'Time': continue # In testing and development we swap the Time library for a ControlledTime version which lets us manage block timestamp contractsToDelegate = ['Orders', 'TradingEscapeHatch', 'Cash'] if name in contractsToDelegate: delegationTargetName = "".join([name, "Target"]) self.uploadAndAddToController(path.join(directory, filename), delegationTargetName, name) self.uploadAndAddToController("../source/contracts/libraries/Delegator.sol", name, "delegator", constructorArgs=[self.contracts['Controller'].address, delegationTargetName.ljust(32, '\x00')]) self.contracts[name] = self.applySignature(name, self.contracts[name].address) elif name == "TimeControlled": self.uploadAndAddToController(path.join(directory, filename), lookupKey = "Time", signatureKey = "TimeControlled") elif name == "Trade": self.uploadAndAddToController("solidity_test_helpers/TestTrade.sol", lookupKey = "Trade", signatureKey = "Trade") else: self.uploadAndAddToController(path.join(directory, filename)) def uploadAllMockContracts(self): for directory, _, filenames in walk(resolveRelativePath(self.relativeTestContractsPath)): for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if not name.startswith('Mock'): continue if 'Factory' in name: self.upload(path.join(directory, filename)) else: self.uploadAndAddToController(path.join(directory, filename)) def whitelistTradingContracts(self): for filename in listdir(resolveRelativePath('../source/contracts/trading')): name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if name == "ShareToken": continue if not name in self.contracts: continue self.contracts['Controller'].addToWhitelist(self.contracts[name].address) def initializeAllContracts(self): contractsToInitialize = ['CompleteSets','CreateOrder','FillOrder','CancelOrder','Trade','ClaimTradingProceeds','OrdersFetcher', 'Time'] for contractName in contractsToInitialize: if getattr(self.contracts[contractName], "setController", None): self.contracts[contractName].setController(self.contracts['Controller'].address) elif getattr(self.contracts[contractName], "initialize", None): self.contracts[contractName].initialize(self.contracts['Controller'].address) else: raise "contract has neither 'initialize' nor 'setController' method on it." #### #### Helpers #### def getSeededCash(self): cash = self.contracts['Cash'] cash.depositEther(value = 1, sender = tester.k9) return cash def approveCentralAuthority(self): authority = self.contracts['Augur'] contractsToApprove = ['Cash'] testersGivingApproval = [getattr(tester, 'k%i' % x) for x in range(0,10)] for testerKey in testersGivingApproval: for contractName in contractsToApprove: self.contracts[contractName].approve(authority.address, 2**254, sender=testerKey) def uploadAugur(self): # We have to upload Augur first so it can log when contracts are added to the registry augur = self.upload("../source/contracts/Augur.sol") self.contracts["Augur"].setController(self.contracts['Controller'].address) self.contracts['Controller'].registerContract("Augur".ljust(32, '\x00'), augur.address, garbageBytes20, garbageBytes32) return augur def uploadShareToken(self, controllerAddress = None): controllerAddress = controllerAddress if controllerAddress else self.contracts['Controller'].address self.ensureShareTokenDependencies() shareTokenFactory = self.contracts['ShareTokenFactory'] shareToken = shareTokenFactory.createShareToken(controllerAddress) return self.applySignature('shareToken', shareToken) def createUniverse(self): universeAddress = self.contracts['Augur'].createGenesisUniverse() universe = self.applySignature('Universe', universeAddress) assert universe.getTypeName() == stringToBytes('Universe') return universe def getShareToken(self, market, outcome): shareTokenAddress = market.getShareToken(outcome) assert shareTokenAddress shareToken = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['ShareToken']), shareTokenAddress) return shareToken def getOrCreateChildUniverse(self, parentUniverse, market, payoutDistribution): assert payoutDistributionHash childUniverseAddress = parentUniverse.getOrCreateChildUniverse(payoutDistribution, False) assert childUniverseAddress childUniverse = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Universe']), childUniverseAddress) return childUniverse def createBinaryMarket(self, universe, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo=""): marketCreationFee = universe.getOrCacheMarketCreationCost() marketAddress = universe.createBinaryMarket(endTime, feePerEthInWei, denominationToken.address, designatedReporterAddress, topic, description, extraInfo, value = marketCreationFee, sender=sender) assert marketAddress market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createCategoricalMarket(self, universe, numOutcomes, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo=""): marketCreationFee = universe.getOrCacheMarketCreationCost() outcomes = [" "] * numOutcomes marketAddress = universe.createCategoricalMarket(endTime, feePerEthInWei, denominationToken.address, designatedReporterAddress, outcomes, topic, description, extraInfo, value = marketCreationFee, sender=sender) assert marketAddress market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createScalarMarket(self, universe, endTime, feePerEthInWei, denominationToken, maxPrice, minPrice, numTicks, designatedReporterAddress, sender=tester.k0, description="description", extraInfo=""): marketCreationFee = universe.getOrCacheMarketCreationCost() marketAddress = universe.createScalarMarket(endTime, feePerEthInWei, denominationToken.address, designatedReporterAddress, minPrice, maxPrice, numTicks, "", description, extraInfo, value = marketCreationFee, sender=sender) assert marketAddress market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createReasonableBinaryMarket(self, universe, denominationToken, sender=tester.k0, topic="", description="description", extraInfo=""): return self.createBinaryMarket( universe = universe, endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()), feePerEthInWei = 10**16, denominationToken = denominationToken, designatedReporterAddress = tester.a0, sender = sender, topic= topic, description= description, extraInfo= extraInfo) def createReasonableCategoricalMarket(self, universe, numOutcomes, denominationToken, sender=tester.k0): return self.createCategoricalMarket( universe = universe, numOutcomes = numOutcomes, endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()), feePerEthInWei = 10**16, denominationToken = denominationToken, designatedReporterAddress = tester.a0, sender = sender) def createReasonableScalarMarket(self, universe, maxPrice, minPrice, numTicks, denominationToken, sender=tester.k0): return self.createScalarMarket( universe = universe, endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()), feePerEthInWei = 10**16, denominationToken = denominationToken, maxPrice= maxPrice, minPrice= minPrice, numTicks= numTicks, designatedReporterAddress = tester.a0, sender = sender)
class ContractsFixture: signatures = {} compiledCode = {} #### #### Static Methods #### @staticmethod def ensureCacheDirectoryExists(): if not path.exists(COMPILATION_CACHE): makedirs(COMPILATION_CACHE) @staticmethod def generateSignature(relativeFilePath): ContractsFixture.ensureCacheDirectoryExists() filename = path.basename(relativeFilePath) name = path.splitext(filename)[0] outputPath = path.join(COMPILATION_CACHE, name + 'Signature') lastCompilationTime = path.getmtime(outputPath) if path.isfile( outputPath) else 0 if path.getmtime(relativeFilePath) > lastCompilationTime: print('generating signature for ' + name) extension = path.splitext(filename)[1] signature = None if extension == '.sol': signature = ContractsFixture.compileSolidity( relativeFilePath)['abi'] else: raise with open(outputPath, mode='w') as file: json_dump(signature, file) else: print('using cached signature for ' + name) with open(outputPath, 'r') as file: signature = json_load(file) return (signature) @staticmethod def getCompiledCode(relativeFilePath): filename = path.basename(relativeFilePath) name = path.splitext(filename)[0] if name in ContractsFixture.compiledCode: return ContractsFixture.compiledCode[name] dependencySet = set() ContractsFixture.getAllDependencies(relativeFilePath, dependencySet) ContractsFixture.ensureCacheDirectoryExists() compiledOutputPath = path.join(COMPILATION_CACHE, name) lastCompilationTime = path.getmtime(compiledOutputPath) if path.isfile( compiledOutputPath) else 0 needsRecompile = False for dependencyPath in dependencySet: if (path.getmtime(dependencyPath) > lastCompilationTime): needsRecompile = True break if (needsRecompile): print('compiling ' + name + '...') extension = path.splitext(filename)[1] compiledCode = None if extension == '.sol': compiledCode = bytearray.fromhex( ContractsFixture.compileSolidity(relativeFilePath)['evm'] ['bytecode']['object']) else: raise with io_open(compiledOutputPath, mode='wb') as file: file.write(compiledCode) else: print('using cached compilation for ' + name) with io_open(compiledOutputPath, mode='rb') as file: compiledCode = file.read() contractSize = len(compiledCode) if (contractSize >= CONTRACT_SIZE_LIMIT): print('%sContract %s is OVER the size limit by %d bytes%s' % (bcolors.FAIL, name, contractSize - CONTRACT_SIZE_LIMIT, bcolors.ENDC)) elif (contractSize >= CONTRACT_SIZE_WARN_LEVEL): print('%sContract %s is under size limit by only %d bytes%s' % (bcolors.WARN, name, CONTRACT_SIZE_LIMIT - contractSize, bcolors.ENDC)) elif (contractSize > 0): print('Size: %i' % contractSize) ContractsFixture.compiledCode[name] = compiledCode return (compiledCode) @staticmethod def compileSolidity(relativeFilePath): absoluteFilePath = resolveRelativePath(relativeFilePath) filename = path.basename(relativeFilePath) contractName = path.splitext(filename)[0] print absoluteFilePath compilerParameter = { 'language': 'Solidity', 'sources': { absoluteFilePath: { 'urls': [absoluteFilePath] } }, 'settings': { # TODO: Remove 'remappings' line below and update 'sources' line above 'remappings': [ '=%s/' % resolveRelativePath("../source/contracts"), 'TEST=%s/' % resolveRelativePath("solidity_test_helpers") ], 'optimizer': { 'enabled': True, 'runs': 500 }, 'outputSelection': { '*': ['metadata', 'evm.bytecode', 'evm.sourceMap'] } } } return compile_standard( compilerParameter, allow_paths=resolveRelativePath( "../"))['contracts'][absoluteFilePath][contractName] @staticmethod def getAllDependencies(filePath, knownDependencies): knownDependencies.add(filePath) fileDirectory = path.dirname(filePath) with open(filePath, 'r') as file: fileContents = file.read() matches = findall("inset\('(.*?)'\)", fileContents) for match in matches: dependencyPath = path.abspath(path.join(fileDirectory, match)) if not dependencyPath in knownDependencies: ContractsFixture.getAllDependencies(dependencyPath, knownDependencies) matches = findall("create\('(.*?)'\)", fileContents) for match in matches: dependencyPath = path.abspath(path.join(fileDirectory, match)) if not dependencyPath in knownDependencies: ContractsFixture.getAllDependencies(dependencyPath, knownDependencies) matches = findall("import ['\"](.*?)['\"]", fileContents) for match in matches: dependencyPath = path.join(BASE_PATH, '..', 'source/contracts', match) if "TEST" in dependencyPath: dependencyPath = path.join(BASE_PATH, 'solidity_test_helpers', match).replace("TEST/", "") if not path.isfile(dependencyPath): raise Exception("Could not resolve dependency file path: %s" % dependencyPath) if not dependencyPath in knownDependencies: ContractsFixture.getAllDependencies(dependencyPath, knownDependencies) return (knownDependencies) #### #### Class Methods #### def __init__(self): tester.GASPRICE = 0 config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001 config_metropolis['GENESIS_GAS_LIMIT'] = 2**60 config_metropolis['MIN_GAS_LIMIT'] = 2**60 config_metropolis['BLOCK_GAS_LIMIT'] = 2**60 for a in range(10): tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24} self.chain = Chain(env=Env(config=config_metropolis)) self.contracts = {} self.testerAddress = self.generateTesterMap('a') self.testerKey = self.generateTesterMap('k') def distributeRep(self, universe): legacyReputationToken = self.contracts['LegacyReputationToken'] legacyReputationToken.faucet(11 * 10**6 * 10**18) # Get the reputation token for this universe and migrate legacy REP to it reputationToken = self.applySignature('ReputationToken', universe.getReputationToken()) legacyReputationToken.approve(reputationToken.address, 11 * 10**6 * 10**18) reputationToken.migrateFromLegacyReputationToken() def generateTesterMap(self, ch): testers = {} for i in range(0, 9): testers[i] = getattr(tester, ch + "%d" % i) return testers def uploadAndAddToController(self, relativeFilePath, lookupKey=None, signatureKey=None, constructorArgs=[]): lookupKey = lookupKey if lookupKey else path.splitext( path.basename(relativeFilePath))[0] contract = self.upload(relativeFilePath, lookupKey, signatureKey, constructorArgs) if not contract: return None self.contracts['Controller'].registerContract( lookupKey.ljust(32, '\x00'), contract.address, garbageBytes20, garbageBytes32) return (contract) def upload(self, relativeFilePath, lookupKey=None, signatureKey=None, constructorArgs=[]): resolvedPath = resolveRelativePath(relativeFilePath) lookupKey = lookupKey if lookupKey else path.splitext( path.basename(resolvedPath))[0] signatureKey = signatureKey if signatureKey else lookupKey if lookupKey in self.contracts: return (self.contracts[lookupKey]) compiledCode = ContractsFixture.getCompiledCode(resolvedPath) # abstract contracts have a 0-length array for bytecode if len(compiledCode) == 0: print "Skipping upload of " + lookupKey + " because it had no bytecode (likely a abstract class/interface)." return None if signatureKey not in ContractsFixture.signatures: ContractsFixture.signatures[ signatureKey] = ContractsFixture.generateSignature( resolvedPath) signature = ContractsFixture.signatures[signatureKey] contractTranslator = ContractTranslator(signature) if len(constructorArgs) > 0: compiledCode += contractTranslator.encode_constructor_arguments( constructorArgs) contractAddress = bytesToHexString( self.chain.contract(compiledCode, language='evm', startgas=long(6.7 * 10**6))) contract = ABIContract(self.chain, contractTranslator, contractAddress) self.contracts[lookupKey] = contract return (contract) def applySignature(self, signatureName, address): assert address if type(address) is long: address = longToHexString(address) translator = ContractTranslator( ContractsFixture.signatures[signatureName]) contract = ABIContract(self.chain, translator, address) return contract def createSnapshot(self): self.chain.tx(sender=tester.k0, to=tester.a1, value=0) self.chain.mine(1) contractsCopy = {} for contractName in self.contracts: contractsCopy[contractName] = dict( translator=self.contracts[contractName].translator, address=self.contracts[contractName].address) return { 'state': self.chain.head_state.to_snapshot(), 'contracts': contractsCopy } def resetToSnapshot(self, snapshot): if not 'state' in snapshot: raise "snapshot is missing 'state'" if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'" self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis)) self.contracts = {} for contractName in snapshot['contracts']: contract = snapshot['contracts'][contractName] self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address']) #### #### Bulk Operations #### def uploadAllContracts(self): for directory, _, filenames in walk( resolveRelativePath('../source/contracts')): # skip the legacy reputation directory since it is unnecessary and we don't support uploads of contracts with constructors yet if 'legacy_reputation' in directory: continue for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if name == 'controller': continue contractsToDelegate = ['Orders', 'TradingEscapeHatch'] if name in contractsToDelegate: delegationTargetName = "".join([name, "Target"]) self.uploadAndAddToController( path.join(directory, filename), delegationTargetName, name) self.uploadAndAddToController( "../source/contracts/libraries/Delegator.sol", name, "delegator", constructorArgs=[ self.contracts['Controller'].address, delegationTargetName.ljust(32, '\x00') ]) self.contracts[name] = self.applySignature( name, self.contracts[name].address) else: self.uploadAndAddToController( path.join(directory, filename)) def uploadAllMockContracts(self): for directory, _, filenames in walk( resolveRelativePath('solidity_test_helpers')): for filename in filenames: name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if not name.startswith('Mock'): continue if 'Factory' in name: self.upload(path.join(directory, filename)) else: self.uploadAndAddToController( path.join(directory, filename)) def whitelistTradingContracts(self): for filename in listdir( resolveRelativePath('../source/contracts/trading')): name = path.splitext(filename)[0] extension = path.splitext(filename)[1] if extension != '.sol': continue if not name in self.contracts: continue self.contracts['Controller'].addToWhitelist( self.contracts[name].address) def initializeAllContracts(self): contractsToInitialize = [ 'Augur', 'Cash', 'CompleteSets', 'CreateOrder', 'FillOrder', 'CancelOrder', 'Trade', 'ClaimTradingProceeds', 'OrdersFetcher' ] for contractName in contractsToInitialize: if getattr(self.contracts[contractName], "setController", None): self.contracts[contractName].setController( self.contracts['Controller'].address) elif getattr(self.contracts[contractName], "initialize", None): self.contracts[contractName].initialize( self.contracts['Controller'].address) else: raise "contract has neither 'initialize' nor 'setController' method on it." #### #### Helpers #### def getSeededCash(self): cash = self.contracts['Cash'] cash.depositEther(value=1, sender=tester.k9) return cash def approveCentralAuthority(self): authority = self.contracts['Augur'] contractsToApprove = ['Cash'] testersGivingApproval = [ getattr(tester, 'k%i' % x) for x in range(0, 10) ] for testerKey in testersGivingApproval: for contractName in contractsToApprove: self.contracts[contractName].approve(authority.address, 2**254, sender=testerKey) def uploadShareToken(self, controllerAddress=None): controllerAddress = controllerAddress if controllerAddress else self.contracts[ 'Controller'].address self.ensureShareTokenDependencies() shareTokenFactory = self.contracts['ShareTokenFactory'] shareToken = shareTokenFactory.createShareToken(controllerAddress) return self.applySignature('shareToken', shareToken) def createUniverse(self, parentUniverse, payoutDistributionHash): universeAddress = self.contracts['UniverseFactory'].createUniverse( self.contracts['Controller'].address, parentUniverse, payoutDistributionHash) universe = self.applySignature('Universe', universeAddress) assert universe.getTypeName() == stringToBytes('Universe') return universe def getStakeToken(self, market, payoutDistribution, invalid=False): stakeTokenAddress = market.getStakeToken(payoutDistribution, invalid) assert stakeTokenAddress stakeToken = ABIContract( self.chain, ContractTranslator(ContractsFixture.signatures['StakeToken']), stakeTokenAddress) return stakeToken def getShareToken(self, market, outcome): shareTokenAddress = market.getShareToken(outcome) assert shareTokenAddress shareToken = ABIContract( self.chain, ContractTranslator(ContractsFixture.signatures['ShareToken']), shareTokenAddress) return shareToken def designatedReport(self, market, payoutDistribution, reporterKey, invalid=False): stakeToken = self.getStakeToken(market, payoutDistribution, invalid) universe = self.applySignature('Universe', market.getUniverse()) designatedReportStake = universe.getDesignatedReportStake() return stakeToken.buy(designatedReportStake, sender=reporterKey) def getOrCreateChildUniverse(self, parentUniverse, market, payoutDistribution): payoutDistributionHash = market.derivePayoutDistributionHash( payoutDistribution, False) assert payoutDistributionHash childUniverseAddress = parentUniverse.getOrCreateChildUniverse( payoutDistributionHash) assert childUniverseAddress childUniverse = ABIContract( self.chain, ContractTranslator(ContractsFixture.signatures['Universe']), childUniverseAddress) return childUniverse def createBinaryMarket(self, universe, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, numTicks, sender=tester.k0, extraInfo=""): return self.createCategoricalMarket(universe, 2, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, numTicks, sender, extraInfo) def createCategoricalMarket(self, universe, numOutcomes, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, numTicks, sender=tester.k0, extraInfo=""): marketCreationFee = universe.getMarketCreationCost() reportingWindow = self.applySignature( 'ReportingWindow', universe.getReportingWindowByMarketEndTime(endTime)) marketAddress = reportingWindow.createMarket(endTime, numOutcomes, numTicks, feePerEthInWei, denominationToken.address, designatedReporterAddress, extraInfo, value=marketCreationFee, startgas=long(6.7 * 10**6), sender=sender) assert marketAddress market = ABIContract( self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createScalarMarket(self, universe, endTime, feePerEthInWei, denominationToken, numTicks, designatedReporterAddress, sender=tester.k0): marketCreationFee = universe.getMarketCreationCost() reportingWindow = self.applySignature( 'ReportingWindow', universe.getReportingWindowByMarketEndTime(endTime)) marketAddress = reportingWindow.createMarket(endTime, 2, numTicks, feePerEthInWei, denominationToken.address, designatedReporterAddress, "", value=marketCreationFee, startgas=long(6.7 * 10**6), sender=sender) assert marketAddress market = ABIContract( self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress) return market def createReasonableBinaryMarket(self, universe, denominationToken, sender=tester.k0, extraInfo=""): return self.createBinaryMarket( universe=universe, endTime=long(self.chain.head_state.timestamp + timedelta(days=1).total_seconds()), feePerEthInWei=10**16, denominationToken=denominationToken, designatedReporterAddress=tester.a0, numTicks=10**18, sender=sender, extraInfo=extraInfo) def createReasonableCategoricalMarket(self, universe, numOutcomes, denominationToken, sender=tester.k0): return self.createCategoricalMarket( universe=universe, numOutcomes=numOutcomes, endTime=long(self.chain.head_state.timestamp + timedelta(days=1).total_seconds()), feePerEthInWei=10**16, denominationToken=denominationToken, designatedReporterAddress=tester.a0, numTicks=3 * 10**17, sender=sender) def createReasonableScalarMarket(self, universe, priceRange, denominationToken, sender=tester.k0): return self.createScalarMarket( universe=universe, endTime=long(self.chain.head_state.timestamp + timedelta(days=1).total_seconds()), feePerEthInWei=10**16, denominationToken=denominationToken, numTicks=40 * 10**18, designatedReporterAddress=tester.a0, sender=sender)