0
votes

I've successfully deployed the following contract on Kaleido:

pragma solidity ^0.4.0;

contract Greeter {
    string public greeting;

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

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

    function greet() constant returns (string) {
        return greeting;
    }
}

I try to interact with the contract like so:


from web3 import Web3
from web3.providers import HTTPProvider
from solc import compile_source
from web3.contract import ConciseContract

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

contract Greeter {
    string public greeting;

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

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

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

compiled_sol = compile_source(contract_source_code) 
contract_interface = compiled_sol[':Greeter']

w3 = Web3(HTTPProvider("https://user:[email protected]"))

# address from previous deployment
contract_address = Web3.toChecksumAddress("0x4c94e89d5ec3125339906109f143673f40868df2")

greeter = w3.eth.contract(
    address=contract_address,
    abi=contract_interface['abi'],
)

print('Default contract greeting: {}'.format(
    greeter.functions.greet().call()
))

# --- this hangs ---
print('Setting the greeting to Nihao...')
tx_hash = greeter.functions.setGreeting('Nihao').transact({ 'from': w3.eth.accounts[0], 'gas': 100000})

w3.eth.waitForTransactionReceipt(tx_hash)

print('Updated contract greeting: {}'.format(
    greeter.functions.greet().call()
))

reader = ConciseContract(greeter)
assert reader.greet() == "Nihao"

However, when I try to submit a transaction which calls setGreeting the transaction hangs. Viewing the Kaleido logs, I see VM in read-only mode. Mutating opcode prohibited. Also, when I visit the block explorer for my node, the transactions don't load while the blocks do.

transactions not loading

What can I do about this read only mode?

2

2 Answers

1
votes

moghadasian

I could not recreate your "VM in read-only mode" when submitting a transaction - that worked successfully. However, I had to do a bit of investigation to get web3/python connecting to Kaleido - so I'm adding a separate answer to help others trying to get going.

Configuring HTTPS authentication to Kaleido from Python web3

On my Mac, with a default pip3 installation of web3, I found the only way to configure the Python Session with auth was to use a $HOME/.netrc file such as:

machine u0oaXXXXXX-u0c4XXXXXX-rpc.us-east-2.kaleido.io
login u0d0bxXXXX
password jA-pJdIrcRaIx7XXXXXXXXXXXXXXXXXXXXXXXXX

Configure web3 for Geth/PoA

My chain was using Geth/PoA, so I had to follow the instructions here, to install the required middleware: http://web3py.readthedocs.io/en/stable/middleware.html#geth-style-proof-of-authority

Updated example including deployment of contract

Here is the python3 that successfully deployed and reported Updated contract greeting: Nihao. You will need to change your HTTPProvider to the HTTPS RPC URL of your node, but without the authentication headers.

from web3 import Web3
from web3.providers import HTTPProvider
from solc import compile_source
from web3.contract import ConciseContract
from web3.middleware import geth_poa_middleware

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

contract Greeter {
    string public greeting;

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

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

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

compiled_sol = compile_source(contract_source_code) 
contract_interface = compiled_sol['<stdin>:Greeter']

w3 = Web3(HTTPProvider("https://u0oaXXXXXX-u0c4XXXXXX-rpc.us-east-2.kaleido.io"))
w3.middleware_stack.inject(geth_poa_middleware, layer=0)

Greeter = w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
tx_hash = Greeter.constructor().transact({ 'from': w3.eth.accounts[0], 'gas': 1000000})
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
print('Deployed greeter contract: {}'.format(tx_receipt.contractAddress))

# address from previous deployment
contract_address = Web3.toChecksumAddress(tx_receipt.contractAddress)

greeter = w3.eth.contract(
    address=contract_address,
    abi=contract_interface['abi'],
)

print('Default contract greeting: {}'.format(
    greeter.functions.greet().call()
))

print('Setting the greeting to Nihao...')
tx_hash = greeter.functions.setGreeting('Nihao').transact({ 'from': w3.eth.accounts[0], 'gas': 100000})

w3.eth.waitForTransactionReceipt(tx_hash)

print('Updated contract greeting: {}'.format(
    greeter.functions.greet().call()
))

reader = ConciseContract(greeter)
assert reader.greet() == "Nihao"
1
votes

moghadasian,

The "VM in read-only mode" is because you are using call to interact with your Smart Contract method. So it's just calling your method in a read-only mode. You would use this to call methods on contracts that query data - without having to submit a transaction to the chain.

[edit] - the above advice is generally helpful for "VM in read-only mode", but if you're trying out python web3, you pobably want the other answer with a full working example: https://stackoverflow.com/a/51155413/4972840 [/edit]

Regards, Peter