Пример #1
0
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')
Пример #2
0
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,
                ))
Пример #3
0
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")
Пример #4
0
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)))
Пример #5
0
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
Пример #6
0
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()
Пример #7
0
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)
Пример #8
0
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
Пример #9
0
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
Пример #10
0
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
Пример #11
0
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
Пример #12
0
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
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
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))
Пример #16
0
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
Пример #17
0
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)