def test_get_contracts(mock_project): """ Test that get_contracts() returns proper Web3 contract objects """ with mock_project() as mock: # Setup our environment compiler = Compiler(project_dir=mock.paths.project) compiler.compile_all() # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) deployer_account = web3.eth.accounts[0] # Init the Deployer d = Deployer( network_name=NETWORK_NAME, account=deployer_account, project_dir=mock.paths.project, ) d.deploy() contracts = get_contracts(NETWORK_NAME) assert len(contracts) > 0, "No contracts found" # Make sure it has all the expected Web3 Contract props assert hasattr(contracts['Test'], 'functions') assert hasattr(contracts['Test'], 'address') assert hasattr(contracts['Test'], 'abi')
def test_block_travel(ganache, temp_dir): with ganache() as gopts: with temp_dir() as workdir: networksyml = workdir.joinpath('networks.yml') with networksyml.open('w') as _file: _file.write(NETWORKS_YML_1) web3c._load_configuration(networksyml) web3 = web3c.get_web3(gopts.network_name) start_block = web3.eth.getBlock('latest') blocks_to_travel = 5 latest_block_number = block_travel(web3, blocks_to_travel) latest_block = web3.eth.getBlock(latest_block_number) expected_block = start_block.number + blocks_to_travel assert latest_block.timestamp > start_block.timestamp assert latest_block.number == expected_block, ( "block travel failed. Expected {} blocks, but only saw {} blocks" .format( expected_block, latest_block.number, ))
def test_script_failure(mock_project): """ test that scripts fail properly """ with mock_project() as mock: test_script = mock.paths.scripts.joinpath('test_fail.py') assert test_script.is_file() # Setup our environment compiler = Compiler(project_dir=mock.paths.project) compiler.compile_all() # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) deployer_account = web3.eth.accounts[0] # Init the Deployer d = Deployer( network_name=NETWORK_NAME, account=deployer_account, project_dir=mock.paths.project, ) d.deploy() assert run_script( NETWORK_NAME, str(test_script)) is False, "Script unexpectedly succeeded" assert run_scripts(NETWORK_NAME, [str(test_script)]) is False, ( "Scripts unexpectedly succeeded")
def test_console(mock_project): """ Test the interactive console """ with mock_project() as mock: # Since we're not using the pwd, we need to use this undocumented API (I know...) assert mock.paths.project.joinpath('networks.yml').exists() web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) sc = SolidbyteConsole(network_name=NETWORK_NAME, web3=web3) commands = CONSOLE_TEST_ASSERT_LOCALS.copy() while len(commands) > 0: cmd = commands.pop(0) if 'exit' not in cmd: assert not sc.push( cmd.rstrip('\n')) # Should return false if success else: try: sc.push(cmd.rstrip('\n')) assert False, "Should have exited" except SystemExit as err: """ Since AssertionError exits with code 0 for some reason, our test exits cleanly with code 1337. """ assert str(err) == str(OBVIOUS_RETURN_CODE), ( "Invalid exit code: {}".format(str(err)))
def test_accounts_account_noexist(mock_project): with mock_project() as mock: web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) # Put a file where the keystore dir should be keystore_path = mock.paths.project.joinpath('keystore') keystore_path.mkdir() accounts = Accounts( network_name=NETWORK_NAME, web3=web3, keystore_dir=keystore_path, ) try: accounts.get_account(ADDRESS_2) assert False, "get_account() on invalid address should fail" except FileNotFoundError: pass try: accounts.set_account_attribute(ADDRESS_2, 'what', 'ever') assert False, "set_account_attribute() on invalid address should fail" except IndexError: pass
def test_deployer_deptree(mock_project): """ Test the Deployer dep tree """ with mock_project(with_libraries=True) as mock: # Setup our environment compiler = Compiler(project_dir=mock.paths.project) compiler.compile_all() # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) deployer_account = web3.eth.accounts[0] # Init the Deployer d = Deployer( network_name=NETWORK_NAME, account=deployer_account, project_dir=mock.paths.project, ) deptree = d._build_dependency_tree(force=True) assert isinstance(deptree, ContractDependencyTree) assert deptree.root.has_dependents()
def test_deployer(mock_project): """ Test deploying a project """ """ TODO ---- This is a massive test spanning a ton of components. Can this be broken down at all? Or maybe forced to run last somehow? This is more or less a large integration test. If some small component fails, this test will fail. So if you have multiple tests failing that include this one, start on the other one first. """ with mock_project() as mock: # Setup our environment compiler = Compiler(project_dir=mock.paths.project) compiler.compile_all() # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) deployer_account = web3.eth.accounts[0] # Init the Deployer d = Deployer( network_name=NETWORK_NAME, account=deployer_account, project_dir=mock.paths.project, ) # Test initial state with the mock project assert len(d.artifacts) == 1 contract_key = list(d.artifacts.keys())[0] assert d.artifacts[contract_key].name == 'Test' assert d.artifacts[contract_key].abi is not None assert d.artifacts[contract_key].bytecode is not None assert len(d.deployed_contracts) == 0 # Check that deployment needs to happen assert d.check_needs_deploy() assert d.check_needs_deploy('Test') d._load_user_scripts() assert len(d._deploy_scripts) == 1 # Mock project has 1 deploy script # Run a deployment assert d.deploy(), "Test deployment failed" # Verify it looks complete to the deployer # assert not d.check_needs_deploy() # assert not d.check_needs_deploy('Test') # TODO: Disabled asserts due to a probable bug or bad test env. Look into it. try: d.check_needs_deploy('Nothing') assert False, "check_needs_deploy() should throw when a contract does not exist" except FileNotFoundError as err: assert 'Unknown contract' in str(err)
def test_web3_middleware(mock_project): """ Test the gas report middleware for web3 """ with mock_project() as mock: web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) storage = GasReportStorage() web3.middleware_onion.add( construct_gas_report_middleware(storage), 'gas_report_middleware', ) value = int(1e16) # 0.01 Ether gas = int(1e6) gas_price = int(3e9) assert web3.is_eth_tester joe = web3.eth.accounts[1] jak = web3.eth.accounts[2] tx_hash1 = web3.eth.sendTransaction({ 'from': joe, 'to': jak, 'value': value, 'gas': gas, 'gasPrice': gas_price, 'data': TEST_HASH, }) receipt1 = web3.eth.waitForTransactionReceipt(tx_hash1) tx_hash2 = web3.eth.sendTransaction({ 'from': jak, 'to': joe, 'value': value, 'gas': gas, 'gasPrice': gas_price, 'data': TEST_HASH, }) receipt2 = web3.eth.waitForTransactionReceipt(tx_hash2) try: storage.update_gas_used_from_chain(None) assert False, "update_gas_used_from_chain should have failed without web3" except Exception: pass storage.update_gas_used_from_chain(web3) total_gas = receipt1.gasUsed + receipt2.gasUsed report = storage.get_report() assert report assert sum([sum(x) for x in report.values()]) == total_gas
def test_deployer_contract_with_libraries(mock_project): """ Test the Contract object """ with mock_project(with_libraries=True) as mock: # Setup our environment compiler = Compiler(project_dir=mock.paths.project) compiler.compile_all() # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) deployer_account = web3.eth.accounts[0] # Init the Deployer d = Deployer( network_name=NETWORK_NAME, account=deployer_account, project_dir=mock.paths.project, ) assert d.check_needs_deploy() to_deploy = d.contracts_to_deploy() assert 'SafeMath' in to_deploy assert 'TestMath' in to_deploy assert 'Unnecessary' in to_deploy d.deploy() d.refresh() assert not d.check_needs_deploy() # Update the library # safe_math_filename = 'SafeMath.sol' # safe_math_file = mock.paths.contracts.joinpath(safe_math_filename) # write_temp_file(LIBRARY_SOURCE_FILE_2, safe_math_filename, mock.paths.contracts, # overwrite=True) # assert safe_math_file.is_file() # Update the library unnecessary_filename = 'Unnecessary.sol' unnecessary_file = mock.paths.contracts.joinpath(unnecessary_filename) write_temp_file(LIBRARY_SOURCE_FILE_4, unnecessary_filename, mock.paths.contracts, overwrite=True) assert unnecessary_file.is_file() # Compile it assert compiler.compile(unnecessary_file) is None d.refresh() assert d.check_needs_deploy() to_deploy = d.contracts_to_deploy() assert 'Unnecessary' in to_deploy assert 'TestMath' in to_deploy
def test_create_deploy_tx_without_constructor(mock_project): """ Test deploy transaction creation function """ with mock_project() as mock: web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) tx = create_deploy_tx(web3, LIBRARY_ABI_OBJ_4, LIBRARY_BYTECODE_4, { 'from': web3.eth.accounts[0], 'gasPrice': int(1e9), }) assert tx.get('data') is not None
def test_create_deploy_tx(mock_project): """ Test deploy transaction creation function """ with mock_project() as mock: web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) tx = create_deploy_tx(web3, ABI_OBJ_1, CONTRACT_BIN_1, { 'from': web3.eth.accounts[0], 'gasPrice': int(1e9), }) assert tx.get('data') is not None
def test_create_deploy_tx_invalid(mock_project): with mock_project() as mock: web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) # Missing web3 try: create_deploy_tx(None, ABI_OBJ_1, CONTRACT_BIN_1, { 'from': web3.eth.accounts[0], 'gasPrice': int(1e9), }) assert False, "create_deploy_tx() should fail with missing input" except DeploymentValidationError: pass # Missing ABI try: create_deploy_tx(web3, None, CONTRACT_BIN_1, { 'from': web3.eth.accounts[0], 'gasPrice': int(1e9), }) assert False, "create_deploy_tx() should fail with missing input" except DeploymentValidationError: pass # Missing bytecode try: create_deploy_tx(web3, ABI_OBJ_1, None, { 'from': web3.eth.accounts[0], 'gasPrice': int(1e9), }) assert False, "create_deploy_tx() should fail with missing input" except DeploymentValidationError: pass # Invalid bytecode try: create_deploy_tx(web3, ABI_OBJ_1, '0x', { 'from': web3.eth.accounts[0], 'gasPrice': int(1e9), }) assert False, "create_deploy_tx() should fail with missing input" except DeploymentValidationError: pass
def test_accounts_conflict_file(mock_project): with mock_project() as mock: web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) # Put a file where the keystore dir should be keystore_path = mock.paths.project.joinpath('keystore') keystore_path.touch() try: Accounts( network_name=NETWORK_NAME, web3=web3, keystore_dir=keystore_path, ) assert False, "Accounts.__init__() should fail on flie conflict" except SolidbyteException as err: assert 'Invalid keystore' in str(err)
def test_deployer_no_contracts(mock_project, temp_dir): with mock_project() as mock: with temp_dir() as workdir: assert Path.cwd() == workdir # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) deployer_account = web3.eth.accounts[0] # Init the Deployer try: Deployer( network_name=NETWORK_NAME, account=deployer_account, project_dir=workdir, ) assert False, "Should fail init if missing contracts directory" except FileNotFoundError as err: assert 'contracts directory' in str(err)
def test_time_travel(ganache, temp_dir): with ganache() as gopts: with temp_dir() as workdir: networksyml = workdir.joinpath('networks.yml') with networksyml.open('w') as _file: _file.write(NETWORKS_YML_1) web3c._load_configuration(networksyml) web3 = web3c.get_web3(gopts.network_name) start_block = web3.eth.getBlock('latest') five_minutes = 5 * 60 latest_block_number = time_travel(web3, five_minutes) latest_block = web3.eth.getBlock(latest_block_number) timediff = latest_block.timestamp - start_block.timestamp assert timediff > 0 assert timediff >= five_minutes, ( "time travel failed. Expected {} received {}".format( five_minutes, timediff))
def test_account_creation(temp_dir): with temp_dir() as tmpdir: # Mock up write_temp_file(NETWORKS_YML_1, 'networks.yml', tmpdir, overwrite=True) web3c._load_configuration(tmpdir.joinpath('networks.yml')) web3 = web3c.get_web3(NETWORK_NAME) accounts = Accounts( network_name=NETWORK_NAME, web3=web3, keystore_dir=tmpdir.joinpath('keystore'), ) assert len(accounts.accounts) == 0 accts = accounts.get_accounts() assert len(accts) == 0 new_acct_addr = accounts.create_account(PASSWORD_1) new_acct = accounts.get_account(new_acct_addr) keyfile = Path(new_acct.filename) assert keyfile.exists() privkey = accounts.unlock(new_acct_addr, PASSWORD_1) assert len(privkey) == 32 # Duplicate privkey_check = accounts.unlock(new_acct_addr, PASSWORD_1) assert privkey == privkey_check # Fund the new account funding_txhash = web3.eth.sendTransaction({ 'from': web3.eth.accounts[0], 'to': new_acct_addr, 'value': int(2e18), 'gas': 22000, 'gasPrice': int(3e8) }) funding_receipt = web3.eth.waitForTransactionReceipt(funding_txhash) assert funding_receipt.status == 1, "funding of test account failed" # Sign and send a tx value = int(1e18) # 1 Ether # Should fail without gasPrice try: accounts.sign_tx( new_acct_addr, { 'from': new_acct_addr, 'to': ADDRESS_1, 'value': value, 'gas': 22000, }, PASSWORD_1) except ValidationError as err: assert 'gasPrice' in str(err) raw_tx = accounts.sign_tx( new_acct_addr, { 'from': new_acct_addr, 'to': ADDRESS_1, 'value': value, 'gas': 22000, 'gasPrice': int(3e8) }, PASSWORD_1) assert is_hex(raw_tx.rawTransaction) tx_hash = web3.eth.sendRawTransaction(raw_tx.rawTransaction) assert len(tx_hash) == 32 receipt = web3.eth.waitForTransactionReceipt(tx_hash) assert receipt.status == 1 assert web3.eth.getBalance(ADDRESS_1) == value assert len(accounts.get_accounts()) == 1 accounts.refresh() assert len(accounts.get_accounts()) == 1 # Sign without gasPrice and send a tx # gas price strategy seems broken in web3.py # value = int(1e18) # 1 Ether # raw_tx = accounts.sign_tx(new_acct_addr, { # 'from': new_acct_addr, # 'to': ADDRESS_1, # 'value': value, # 'gas': 22000, # }, PASSWORD_1) # assert is_hex(raw_tx.rawTransaction) # Load from cache accounts._load_accounts() # Make sure we can load the existing files as well accounts2 = Accounts( network_name=NETWORK_NAME, web3=web3, keystore_dir=tmpdir.joinpath('keystore'), ) accounts2 assert len(accounts2.accounts) == 1
def test_contract_with_library(mock_project): """ Test the Contract object """ with mock_project(with_libraries=True) as mock: # Setup our environment compiler = Compiler(project_dir=mock.paths.project) compiler.compile_all() # Since we're not using the pwd, we need to use this undocumented API (I know...) web3c._load_configuration(mock.paths.networksyml) web3 = web3c.get_web3(NETWORK_NAME) meta = MetaFile(project_dir=mock.paths.project) # Get all the file contents from the compiler output unnecessary_bytecode = None # unnecessary_abi = None safemath_bytecode = None # safemath_abi = None # testmath_abi = None testmath_bytecode = None with mock.paths.build.joinpath('Unnecessary', 'Unnecessary.bin').open() as binfile: unnecessary_bytecode = binfile.read() # with mock.paths.build.joinpath('Unnecessary', 'Unnecessary.abi').open() as abifile: # unnecessary_abi = json.loads(abifile.read()) with mock.paths.build.joinpath('SafeMath', 'SafeMath.bin').open() as binfile: safemath_bytecode = binfile.read() # with mock.paths.build.joinpath('SafeMath', 'SafeMath.abi').open() as abifile: # safemath_abi = json.loads(abifile.read()) with mock.paths.build.joinpath('TestMath', 'TestMath.bin').open() as binfile: testmath_bytecode = binfile.read() # with mock.paths.build.joinpath('TestMath', 'TestMath.abi').open() as abifile: # testmath_abi = json.loads(abifile.read()) # Build the expected source objects # unnecessary_source_contract = AttrDict({ # 'name': 'Unnecessary', # 'abi': unnecessary_abi, # 'bytecode': unnecessary_bytecode, # }) # net_id = web3.net.chainId # meta.add('Unnecessary', net_id, -address, -abi, -bytecode-hash) # safemath_source_contract = AttrDict({ # 'name': 'SafeMath', # 'abi': safemath_abi, # 'bytecode': safemath_bytecode, # }) # testmath_source_contract = AttrDict({ # 'name': 'TestMath', # 'abi': testmath_abi, # 'bytecode': testmath_bytecode, # }) # Create the Contract instances to mess around with unnecessary_contract = Contract( name='Unnecessary', network_name=NETWORK_NAME, from_account=web3.eth.accounts[0], metafile=meta, web3=web3, ) # Make sure contract with no deployments has no expected attrs assert repr(unnecessary_contract) == 'Unnecessary' assert unnecessary_contract.is_deployed() is False assert unnecessary_contract.address is None assert unnecessary_contract.abi is None assert unnecessary_contract.bytecode_hash is None safemath_contract = Contract( name='SafeMath', network_name=NETWORK_NAME, from_account=web3.eth.accounts[0], metafile=meta, web3=web3, ) testmath_contract = Contract( name='TestMath', network_name=NETWORK_NAME, from_account=web3.eth.accounts[0], metafile=meta, web3=web3, ) # Verify things look as expected assert unnecessary_contract.check_needs_deployment(unnecessary_bytecode) assert safemath_contract.check_needs_deployment(safemath_bytecode) assert testmath_contract.check_needs_deployment(testmath_bytecode) # Deploy our contracts unnecessary = unnecessary_contract.deployed() safeMath = safemath_contract.deployed(gas=int(5e6)) safeMath_again = safemath_contract.deployed(gas=int(5e6)) assert safeMath.bytecode == safeMath_again.bytecode assert safeMath.address == safeMath_again.address assert safeMath.address is not None testMath = testmath_contract.deployed(gas=int(5e6), links={ 'SafeMath': safeMath.address, 'Unnecessary': unnecessary.address, }) # Test that everything is working assert testMath.functions.mul(3, 2).call() == 6 assert testMath.functions.div(6, 3).call() == 2 # Update the library unnecessary_filename = 'Unnecessary.sol' unnecessary_file = mock.paths.contracts.joinpath(unnecessary_filename) write_temp_file(LIBRARY_SOURCE_FILE_4, unnecessary_filename, mock.paths.contracts, overwrite=True) assert unnecessary_file.is_file() # Compile it assert compiler.compile(unnecessary_file) is None new_bytecode = None with mock.paths.build.joinpath('Unnecessary', 'Unnecessary.bin').open() as binfile: new_bytecode = binfile.read() # Make sure the Contract instances know they need to be deployed assert unnecessary_contract.check_needs_deployment(new_bytecode)