ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.03k stars 5.7k forks source link

solc.exceptions.SolcError #5984

Closed ammarqureshi closed 5 years ago

ammarqureshi commented 5 years ago

OS: MacOs Mojave I am new to solidity and was following the docs to install the solidity compiler. I successfully installed the solidity compiler. However, when following one the web3.py example:


import json
import web3
import solc
from web3 import Web3
from solc import compile_source
from web3.contract import ConciseContract

# Solidity source code
contract_source_code = '''
pragma solidity ^0.4.21;

contract Greeter {
    string public greeting;

    function Greeter() public {
        greeting = 'Hello';
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string) {
        return greeting;
    }
}
'''

compiled_sol = compile_source(contract_source_code) # Compiled source code
contract_interface = compiled_sol['<stdin>:Greeter']

# web3.py instance
w3 = Web3(Web3.EthereumTesterProvider())

# set pre-funded account as sender
w3.eth.defaultAccount = w3.eth.accounts[0]

# Instantiate and deploy contract
Greeter = w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])

# Submit the transaction that deploys the contract
tx_hash = Greeter.constructor().transact()

# Wait for the transaction to be mined, and get the transaction receipt
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)

# Create the contract instance with the newly-deployed address
greeter = w3.eth.contract(
    address=tx_receipt.contractAddress,
    abi=contract_interface['abi'],
)

# Display the default greeting from the contract
print('Default contract greeting: {}'.format(
    greeter.functions.greet().call()
))

print('Setting the greeting to Nihao...')
tx_hash = greeter.functions.setGreeting('Nihao').transact()

# Wait for transaction to be mined...
w3.eth.waitForTransactionReceipt(tx_hash)

# Display the new greeting value
print('Updated contract greeting: {}'.format(
    greeter.functions.greet().call()
))

# When issuing a lot of reads, try this more concise reader:
reader = ConciseContract(greeter)
assert reader.greet() == "Nihao"

I encounter the following error:

Ammars-MacBook-Pro:Contracts ammarqureshi$ python contract.py
Traceback (most recent call last):
  File "contract.py", line 29, in <module>
    compiled_sol = compile_source(contract_source_code) # Compiled source code
  File "/Users/ammarqureshi/anaconda/lib/python3.6/site-packages/solc/main.py", line 108, in compile_source
    stdoutdata, stderrdata, command, proc = solc_wrapper(**compiler_kwargs)
  File "/Users/ammarqureshi/anaconda/lib/python3.6/site-packages/solc/utils/string.py", line 85, in inner
    return force_obj_to_text(fn(*args, **kwargs))
  File "/Users/ammarqureshi/anaconda/lib/python3.6/site-packages/solc/wrapper.py", line 169, in solc_wrapper
    stderr_data=stderrdata,
solc.exceptions.SolcError: An error occurred during execution
> command: `solc --combined-json abi,asm,ast,bin,bin-runtime,clone-bin,devdoc,interface,opcodes,userdoc`
> return code: `1`
> stderr:

> stdout:
Invalid option to --combined-json: clone-bin
chriseth commented 5 years ago

You seem to be using the "combined-json" way for compiling. This is a legacy feature we do not fully support anymore. The "clone binary" (clone-bin) option was removed a while ago, for example.

Please take a look at the py-solc documentation and look for Standard JSON Compilation.

Please reopen if you encounter further problems.

ammarqureshi commented 5 years ago

@chriseth I tried following the doc you provided. With standard JSON compilation, I have:

from solc import compile_standard

compile_standard({
'language': 'Solidity',
'sources': {'Foo.sol': 'content':
"
pragma solidity ^0.4.21;

contract Greeter {
    string public greeting;

    function Greeter() public {
        greeting = 'Hello';
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string) {
        return greeting;
    }
}

"
}
})

I get the following error:

    'sources': {'Foo.sol': 'content':
                                    ^
    SyntaxError: invalid syntax
ekpyron commented 5 years ago

@ammarqureshi Try:

{
    "language": "Solidity",
    "sources": {
        "Foo.sol": {
            "content": "
pragma solidity ^0.4.21;

contract Greeter {
    string public greeting;

    function Greeter() public {
        greeting = 'Hello';
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string) {
        return greeting;
    }
}

"
        }
    }
}
ammarqureshi commented 5 years ago

@ekpyron I've tried running your code:

from solc import compile_standard
compile_standard(
{
    "language": "Solidity",
    "sources": {
        "Foo.sol": {
            "content": "
pragma solidity ^0.4.21;

contract Greeter {
    string public greeting;

    function Greeter() public {
        greeting = 'Hello';
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string) {
        return greeting;
    }
}

"
        }
    }
}

)

Seems to give the same issue:

(env) Ammars-MacBook-Pro:envs ammarqureshi$ python contract.py 
  File "contract.py", line 7
    "content": "
               ^
SyntaxError: EOL while scanning string literal
ekpyron commented 5 years ago

Ah, sorry, I hadn't read the issue carefully and didn't realize that you're referring to python. You need a proper python multiline string, try:

from solc import compile_standard
compile_standard(
{
    "language": "Solidity",
    "sources": {
        "Foo.sol": {
            "content": '''
pragma solidity ^0.4.21;

contract Greeter {
    string public greeting;

    function Greeter() public {
        greeting = 'Hello';
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string) {
        return greeting;
    }
}
'''
        }
    }
}
)
ammarqureshi commented 5 years ago

@ekpyron got another error:

Ammars-MacBook-Pro:Contracts ammarqureshi$ python contract.py
Traceback (most recent call last):
  File "contract.py", line 25, in <module>
    '''
  File "/Users/ammarqureshi/anaconda/lib/python3.6/site-packages/solc/main.py", line 181, in compile_standard
    message=error_message,
solc.exceptions.SolcError: Foo.sol:4:1: ParserError: Source file requires different compiler version (current compiler is 0.5.4+commit.9549d8ff.Darwin.appleclang - note that nightly builds are considered to be strictly less than the released version
contract Greeter {
^------^

        > command: `solc --standard-json`
        > return code: `0`
        > stderr:
        {"errors":[{"component":"general","formattedMessage":"Foo.sol:4:1: ParserError: Source file requires different compiler version (current compiler is 0.5.4+commit.9549d8ff.Darwin.appleclang - note that nightly builds are considered to be strictly less than the released version\ncontract Greeter {\n^------^\n","message":"Source file requires different compiler version (current compiler is 0.5.4+commit.9549d8ff.Darwin.appleclang - note that nightly builds are considered to be strictly less than the released version","severity":"error","sourceLocation":{"end":35,"file":"Foo.sol","start":27},"type":"ParserError"}],"sources":{}}

        > stdout:

The contract code:

from solc import compile_standard
compile_standard(
{
    "language": "Solidity",
    "sources": {
        "Foo.sol": {
            "content": '''
pragma solidity ^0.4.21;

contract Greeter {
    string public greeting;

    function Greeter() public {
        greeting = 'Hello';
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string) {
        return greeting;
    }
}
'''
        }
    }
}
)

When I run pip install py-solc I got:

Ammars-MacBook-Pro:Contracts ammarqureshi$ pip install py-solc
Collecting py-solc
  Using cached https://files.pythonhosted.org/packages/47/74/d36abca3f36ccdcd04976c50f83502c870623e5beb4a4ec96c7bad4bb9e8/py_solc-3.2.0-py3-none-any.whl
Requirement already satisfied: semantic-version>=2.6.0 in /Users/ammarqureshi/anaconda/lib/python3.6/site-packages (from py-solc) (2.6.0)
ethpm 0.1.4a10 has requirement web3[tester]<6,>=5.0.0a3, but you'll have web3 4.8.2 which is incompatible.
Installing collected packages: py-solc
Successfully installed py-solc-3.2.0
ekpyron commented 5 years ago

Well, you need to use the right compiler version - which one are you aiming for? solc --version should tell you that. Or you replace pragma solidity ^0.4.21; by pragma solidity >0.0.0; to match all compiler versions. Depending on the version you're using you might have to update the Code to be compatible with it as well (e.g. starting from 0.5.0 you need to use constructor() instead of function Greeter(), etc.).

ekpyron commented 5 years ago

From the error message it looks like you're using solc version 0.5.4, so you need to change the contract code to:

pragma solidity ^0.5.0;
contract Greeter {
    string public greeting;

    constructor() public {
        greeting = 'Hello';
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string memory) {
        return greeting;
    }
}
ammarqureshi commented 5 years ago

@ekpyron Thanks for the above response, learning quite a bit here.

Now that the previous way of compiling is not fully supported, how would we go about getting the abi and the bytecode?

The web3.py docs example shows:

contract_interface = compiled_sol['<stdin>:Greeter']

# web3.py instance
w3 = Web3(Web3.EthereumTesterProvider())

# set pre-funded account as sender
w3.eth.defaultAccount = w3.eth.accounts[0]

# Instantiate and deploy contract
Greeter = w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])

After compiling the script:

from solc import compile_standard
compiled_sol = compile_standard(
{
    "language": "Solidity",
    "sources": {
        "Foo.sol": {
            "content": '''
pragma solidity ^0.5.0;
contract Greeter {
    string public greeting;

    constructor() public {
        greeting = 'Hello';
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }

    function greet() view public returns (string memory) {
        return greeting;
    }
}
'''
        }
    }
}
)

print('compiled sol', compiled_sol);

I get:

Ammars-MacBook-Pro:Contracts ammarqureshi$ python contract.py
compiled sol {'sources': {'Foo.sol': {'id': 0}}}
ekpyron commented 5 years ago

For that you can refer to the documentation of the standard-json interface: https://solidity.readthedocs.io/en/v0.5.4/using-the-compiler.html#compiler-input-and-output-json-description Especially the part concerning outputSelection. You should find all the information you need to adjust the query to your needs there.

ammarqureshi commented 5 years ago

Thanks for the response. I have managed to retrieve the bytecode object with:

bytecode = compiled_sol['contracts']['Foo.sol']['Greeter']['evm']['bytecode']['object']

However, having bit of a trouble with retrieving abi. This is what I get back with compiled_sol['contracts']['Foo.sol']['Greeter']['metadata']

{"compiler":{"version":"0.5.4+commit.9549d8ff"},"language":"Solidity","output":{"abi":[{"constant":false,"inputs":[{"name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"greeting","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"Foo.sol":"Greeter"},"evmVersion":"byzantium","libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Foo.sol":{"keccak256":"0x88fcdcf7813c0d045fe2d0f76bac1065d9a5bc04ed41d8bfd7df06c9b0dc9cb0","urls":["bzzr://4be12bc0e7b38c04cac900a11d775ffc953ee16b6ab87f2e5239d9102c5be727"]}},"version":1}

I thought to get abi it would be similar to getting the bytecode object.

compiled_sol['contracts']['Foo.sol']['Greeter']['metadata']['compiler]['output']

but instead I get:

Traceback (most recent call last):
  File "contract.py", line 56, in <module>
    print('compiled ABI', compiled_sol['contracts']['Foo.sol']['Greeter']['metadata']['compiler']);
TypeError: string indices must be integers
ekpyron commented 5 years ago

You should count the brackets in the output ;-).

ammarqureshi commented 5 years ago

@ekpyron

compiled_sol['contracts']['Foo.sol']['Greeter']['metadata']['output']

I still get the same error:

    print('compiled ABI: {}'.format(compiled_sol['contracts']['Foo.sol']['Greeter']['metadata']['output']))
TypeError: string indices must be integers
ekpyron commented 5 years ago

Actually this is the wrong place to ask these questions, since the issues you're having are specific to py-solc, resp. python, not to solidity :-). That being said I guess that the python API just passes you the metadata as string and does not parse it as a python data structure, so you can't access it using ['...'], but you have to use some other means to parse it (which is another issue that's unrelated to solidity - you can probably use the json library shipped with python to decode the string).

ammarqureshi commented 5 years ago

my bad I did not know. Anyways, thanks for the previous help! 👍