HydraChain / hydrachain

Permissioned Distributed Ledger based on Ethereum
MIT License
358 stars 105 forks source link

After initializing a contract in post_app_start_callbacks, it behaves as it is still not initialized #72

Closed 4gn3s closed 8 years ago

4gn3s commented 8 years ago

I deploy and initialize the Fungible contract in a callback added to post_app_start_callbacks. The init runs correctly, and adds an address to the dictionary as expected. However, when I later try to interact with the contract, all the contract's data is as if it was not initialized (returns empty values). I've tried adding wait_next_block_factory(app) after the init and before the interaction, but it does not change anything.

This is my test code:

def test_contract_callback(app):
    if app.services.accounts.coinbase == app.config['hdc']['validators'][0]:
        if app.services.chain.chain.head.number == 0:

            from hydrachain.examples.native.fungible.fungible_contract import Fungible
            from hydrachain.native_contracts import chain_nac_proxy
            from hydrachain.nc_utils import create_contract_instance

            nc.registry.register(Fungible)
            tx_reg_address = create_contract_instance(app, app.services.accounts.coinbase, Fungible)
            proxy = chain_nac_proxy(app.services.chain.chain, app.services.accounts.coinbase, tx_reg_address)
            initial_value = 10000
            proxy.init(initial_value)
            assert proxy.balanceOf(app.services.accounts.coinbase) == initial_value

The assertion fails.

I'm adding the callback in HPCApp:

    default_config['post_app_start_callbacks'] = [test_contract_callback]

I have also added some logging to the Fungible contract, to see what's going on: In init, before the final return statement, and in balanceOf, I'm using:

        for key in ctx.accounts.keys():
            log.info(utils.encode_hex(key))

which in init prints out one key (as expected), but in balanceOf it does not print anything. Why can't I interact with the contract?

RomanZacharia commented 8 years ago

Agnes, Your example fails because the chain_nac_proxy is a tester method and it does not commit transactions into the chain (it applies the tx on the temporary block). Please try the following code sample: `from ethereum.tester import accounts from examples.native.fungible.fungible_contract import Fungible

from hydrachain.nc_utils import create_contract_instance, OK, wait_next_block_factory import hydrachain.native_contracts as nc

from hydrachain.native_contracts import registry import ethereum.processblock as processblock from ethereum.transactions import Transaction from ethereum import slogging slogging.configure(config_string=':debug') log = slogging.get_logger('nc')

def nc_call(block, sender, to, data='', gasprice=0, value=0):

apply transaction

startgas = block.gas_limit - block.gas_used
gasprice = 0
nonce = block.get_nonce(sender)
tx = Transaction(nonce, gasprice, startgas, to, value, data)
tx.sender = sender
try:
    success, output = processblock.apply_transaction(block, tx)
except processblock.InvalidTransaction as e:
    success = False
if success:
    return output
else:
    log.debug('nc_call failed', error=e)
    return None

def nc_proxy(chain, sender, contract_address, value=0): "create an object which acts as a proxy for the contract on the chain" klass = registry[contract_address].im_self assert issubclass(klass, nc.NativeABIContract)

def mk_method(method):
    def m(s, *args):
        data = nc.abi_encode_args(method, args)
        block = chain.head_candidate
        output = nc_call(block, sender, contract_address, data)
        if output is not None:
            return nc.abi_decode_return_vals(method, output)
    return m

class cproxy(object):
    pass
for m in klass._abi_methods():
    setattr(cproxy, m.__func__.func_name, mk_method(m))

return cproxy()

def try_interact(app, coinbase): nc.registry.register(Fungible) tx_reg_address = create_contract_instance(app, coinbase, Fungible) proxy = nc_proxy(app.services.chain.chain, coinbase, tx_reg_address)

total = 10000
transfer_amount = 10

proxy.init(total)

wait_next_block_factory(app)()
assert proxy.totalSupply() == total
assert proxy.balanceOf(coinbase) == total
assert proxy.transfer(accounts[0], transfer_amount) == OK
assert proxy.balanceOf(coinbase) == total - transfer_amount
assert proxy.balanceOf(accounts[0]) == transfer_amount

`

4gn3s commented 8 years ago

Thank you @RomanZacharia, it is indeed working. I will try to add some docs to the main native contracts methods. Closing as solved.