Beispiel #1
0
def participate_account(account_address, deployed_contracts) -> List:
    """
    Make the given account participate.

    :param account_address: address to the account to participate
    :param deployed_contracts: instances of the deployed contracts
    :return: list of coins
    """
    plasma_address = deployed_contracts.plasma_instance.address

    # transfering erc20 tokens to account fro plasma participation
    erc20_transfer(account_address, w3.toWei(ETHER_ALLOC, ETHER_NAME), deployed_contracts.erc20_instance)

    # approve tokens to plasma address so when participate function is called the
    # tokens will be transferred to the plasma address
    erc20_approve(plasma_address, account_address, w3.toWei(ETHER_ALLOC, ETHER_NAME), deployed_contracts.erc20_instance)

    # allocate 10 tokens to plasma
    tokens = participate(deployed_contracts, account_address, TOKEN_ALLOC, COIN_DENOMINATION)
    return tokens
Beispiel #2
0
def test_out_of_funds_participate(setup):
    """
        user owns 10 dock tokens in decimals
        and approves 5 dock tokens to plasma plasma
        user wants to mint(participate) 2 times to plasma with coin denomination 5
        he can't do that since the amount approved is 5 dock tokens in decimals
    """
    accounts, deployed_contracts = setup
    peter_addr = accounts[1].address
    oscar_addr = accounts[3].address

    plasma_address = deployed_contracts.plasma_instance.address
    helpers.utils.erc20_transfer(oscar_addr, w3.toWei(10, ETHER_NAME),
                                 deployed_contracts.erc20_instance)
    helpers.utils.erc20_approve(plasma_address, peter_addr,
                                w3.toWei(5, ETHER_NAME),
                                deployed_contracts.erc20_instance)
    denomination = w3.toWei(5, ETHER_NAME)
    with pytest.raises(Exception):
        utils.participate(deployed_contracts, oscar_addr, 2, denomination)
Beispiel #3
0
def generate_tx(token_id, prev_block, denomination, addr_to, addr_from) -> Dict:
    """
    Generate tx that will be used off-chain to initiate transactions which will also be used to exit or challenge a coin

    :param token_id: id of the token we want to generate a tx for
    :param prev_block: prevBlock of the token.
    :param denomination: token denomination
    :param addr_to: address were the token is being sent
    :param addr_from: address that initiates the transaction
    :return: Dictionary with signature and rlp encoded transaction.
    """
    tx = rlp.encode([token_id, prev_block, denomination, bytes.fromhex(addr_to[2:])])

    if prev_block == 0:
        # This is a deposit transaction.
        # the kecca256 of token id since this is a deposit.
        tx_hash = w3.soliditySha3(['uint64'], [token_id])

        w3.personal.unlockAccount(addr_from, DEFAULT_PASSWORD)
        signature = w3.eth.sign(addr_from, data=tx_hash)
        tx = {
            "signature": signature,
            "tx": tx
        }
        return tx

    else:
        # Else the token was transferred before off-chain.

        # the hash of the tx encoded bytes.
        tx_hash = w3.soliditySha3(['bytes'], [tx])

        w3.personal.unlockAccount(addr_from, DEFAULT_PASSWORD)
        signature = w3.eth.sign(addr_from, data=tx_hash)
        tx = {
            "signature": signature,
            "tx": tx,
            "tx_hash": tx_hash
        }
        return tx
Beispiel #4
0
def test_unauthorized_user_submition(setup):
    accounts, deployed_contracts = setup
    alice_addr = accounts[1].address

    plasma_instance = deployed_contracts.plasma_instance

    root = w3.soliditySha3(['string'], ['test'])

    with pytest.raises(Exception):
        args = (0, root)
        kwargs = {'from': alice_addr}
        fn_submit = plasma_instance.functions.submitBlock(*args)
        kwargs['gas'] = fn_submit.estimateGas()
        w3.personal.unlockAccount(alice_addr, DEFAULT_PASSWORD)
        tx_hash = fn_submit.transact(kwargs)
        assert w3.eth.waitForTransactionReceipt(tx_hash).status
Beispiel #5
0
def test_unsuccessful_block_submition(setup):
    '''
        fails as block number provided is not greater than current block on smart contract
    '''
    _, deployed_contracts = setup
    plasma_instance = deployed_contracts.plasma_instance

    root = w3.soliditySha3(['string'], ['test'])

    with pytest.raises(Exception):
        args = (0, root)
        kwargs = {'from': w3.eth.accounts[0]}

        w3.personal.unlockAccount(w3.eth.defaultAccount, '')
        fn_submit = plasma_instance.functions.submitBlock(*args)
        kwargs['gas'] = fn_submit.estimateGas(kwargs)
        tx_hash = fn_submit.transact(kwargs)
        assert w3.eth.waitForTransactionReceipt(tx_hash).status
Beispiel #6
0
def generate_dummy_tx() -> List:
    """
    Generate dummy transactions to be included in a sparse merkle tree.

    Used so the sparse merkle tree doesn't have only one transaction.
    :return: List with id and transaction hash.
    """
    uid = random.getrandbits(64)
    prevBlock = 5
    deno = 20
    owner = bytes.fromhex("30e3862ceb1a9b8b227bd2a53948c2ba2f1aa54a")

    tx = rlp.encode([uid, prevBlock, deno, owner])

    tx_hash = HexBytes(
        w3.soliditySha3(['bytes'], [tx])  # dummy hash(leaf)
    )

    tx = [uid, tx_hash]

    return tx
Beispiel #7
0
def test_successful_block_submition(setup):
    '''
        successful submission of a block on-chain
        sparse_merkle_tree not included since the test is done just to see if
        values are being stored as expected.
    '''
    _, deployed_contracts = setup
    plasma_instance = deployed_contracts.plasma_instance

    # dummy root hash
    root = w3.soliditySha3(['string'], ['test'])
    args = (1_000, root)
    kwargs = {'from': w3.eth.accounts[0]}

    w3.personal.unlockAccount(w3.eth.defaultAccount, '')
    fn_submit = plasma_instance.functions.submitBlock(*args)
    kwargs['gas'] = fn_submit.estimateGas(kwargs)
    tx_hash = fn_submit.transact(kwargs)
    assert w3.eth.waitForTransactionReceipt(tx_hash).status

    root_on_contract = plasma_instance.functions.childChain(1_000).call()
    assert root_on_contract[0] == root
Beispiel #8
0
def test_unsuccessful_participate(setup):
    """
        user owns and approves tokens to plasma contract
        and should not be able to create DOCK token with different denomination
    """
    accounts, deployed_contracts = setup
    alice_addr = accounts[2].address

    wrong_denomination = 6_000
    assert wrong_denomination != COIN_DENOMINATION

    plasma_address = deployed_contracts.plasma_instance.address

    helpers.utils.erc20_transfer(alice_addr, COIN_DENOMINATION,
                                 deployed_contracts.erc20_instance)
    helpers.utils.erc20_approve(plasma_address, alice_addr, COIN_DENOMINATION,
                                deployed_contracts.erc20_instance)

    new_denomination = w3.toWei(wrong_denomination, ETHER_NAME)

    with pytest.raises(Exception):
        utils.participate(deployed_contracts, alice_addr, 1, new_denomination)
Beispiel #9
0
def test_challenge_5(setup_participate):
    '''
        A group of participants gathered together with operator try to exit alice legitimately owned coin...
        bob in colaboration with operator pretends he received the coin from alice and includes it in a block...
        bob sends coin to oscar...
        oscar sends coin to charlie...
        charlie sends coin to peter...
        peter start exit...
        One of the group members challenges peter...
        alice also challenges with her legit deposit transaction...
    '''
    accounts, deployed_contracts, coins = setup_participate
    alice_addr = accounts[1].address
    bob_addr = accounts[2].address
    oscar_addr = accounts[3].address
    charlie_addr = accounts[4].address
    peter_addr = accounts[5].address

    # deposit tx of alice / legit
    token_uid = next(COIN_COUNTER)
    previous_block = 0
    args = (coins[token_uid], previous_block, COIN_DENOMINATION, alice_addr, alice_addr)
    alice_alice = helpers.utils.generate_tx(*args)

    # Loid pretends she received coin from alice
    previous_block = deployed_contracts.plasma_instance.functions.getPlasmaCoin(coins[token_uid]).call()[1]
    args = (coins[token_uid], previous_block, COIN_DENOMINATION, bob_addr, bob_addr)
    alice_bob = helpers.utils.generate_tx(*args)

    # plasma block is generated and submited to mainnet
    block_height = next(BLOCK_COUNTER)
    args = (deployed_contracts.plasma_instance, coins[token_uid], alice_bob["tx_hash"], block_height)
    alice_bob["proof"], alice_bob["block_number"] = helpers.utils.generate_block(*args)

    # bob sends coin to oscar
    bob_oscar = helpers.utils.generate_tx(
        coins[token_uid],
        alice_bob["block_number"],
        COIN_DENOMINATION,
        oscar_addr,
        bob_addr)

    # plasma block is generated and submited to mainnet
    block_height = next(BLOCK_COUNTER)
    args = (deployed_contracts.plasma_instance, coins[token_uid], bob_oscar["tx_hash"], block_height)
    bob_oscar["proof"], bob_oscar["block_number"] = helpers.utils.generate_block(*args)

    # oscar sends coin to charlie
    oscar_charlie = helpers.utils.generate_tx(
        coins[token_uid],
        bob_oscar["block_number"],
        COIN_DENOMINATION,
        charlie_addr,
        oscar_addr)

    # plasma block is generated and submited to mainnet
    block_height = next(BLOCK_COUNTER)
    args = (deployed_contracts.plasma_instance, coins[token_uid], oscar_charlie["tx_hash"], block_height)
    oscar_charlie["proof"], oscar_charlie["block_number"] = helpers.utils.generate_block(*args)

    # charlie sends coin to peter
    charlie_peter = helpers.utils.generate_tx(
        coins[token_uid],
        oscar_charlie["block_number"],
        COIN_DENOMINATION,
        peter_addr,
        charlie_addr)

    # plasma block is generated and submited to mainnet
    block_height = next(BLOCK_COUNTER)
    args = (deployed_contracts.plasma_instance, coins[token_uid], charlie_peter["tx_hash"], block_height)
    charlie_peter["proof"], charlie_peter["block_number"] = helpers.utils.generate_block(*args)

    # peter starts exits
    events.start_exit(
        deployed_contracts.plasma_instance,
        coins[token_uid],
        oscar_charlie["tx"],
        charlie_peter["tx"],
        oscar_charlie["proof"],
        charlie_peter["proof"],
        charlie_peter["signature"],
        [oscar_charlie["block_number"], charlie_peter["block_number"]],
        peter_addr
    )

    # oscar challenges
    helpers.events.challenge_before(
        deployed_contracts.plasma_instance,
        coins[token_uid],
        bob_oscar["tx"],
        bob_oscar["proof"],
        bob_oscar["signature"],
        18000,
        oscar_addr,
        bob_oscar["tx_hash"]
    )

    # alice also challenges with her valid deposit tx
    helpers.events.challenge_before(
        deployed_contracts.plasma_instance,
        coins[token_uid],
        alice_alice["tx"],
        '0x',
        alice_alice["signature"],
        8,
        alice_addr,
        w3.soliditySha3(['uint64'], [coins[token_uid]])
    )

    # charlie tries to respond challenges / can respond to first challenge but
    # not to alice since it is the valid one.
    helpers.events.respond_challenge_before(
        deployed_contracts.plasma_instance,
        coins[token_uid],
        bob_oscar["tx_hash"],
        oscar_charlie["block_number"],
        oscar_charlie["tx"],
        oscar_charlie["proof"],
        oscar_charlie["signature"],
        charlie_addr
    )

    # alice finishes exit since she owns the coin
    helpers.events.finish_challenge_exit(deployed_contracts.plasma_instance, coins[token_uid], alice_addr)
    coin_struct = deployed_contracts.plasma_instance.functions.getPlasmaCoin(coins[token_uid]).call()
    assert coin_struct[4] == 0
Beispiel #10
0
def test_challenge_1(setup_participate):
    '''
        alice legitimately has deposited and owns a coin
        bob in colludes with the operator to pretend she received a coin from alice
        operator includes fake tx in block
        bob transfers coin to oscar and oscar tries to exit
    '''
    accounts, deployed_contracts, coins = setup_participate
    alice_addr = accounts[1].address
    bob_addr = accounts[2].address
    oscar_addr = accounts[3].address

    # deposit tx of alice / legit
    token_uid = next(COIN_COUNTER)
    previous_block = 0
    args = (coins[token_uid], previous_block, 20, alice_addr, alice_addr)
    alice_alice = helpers.utils.generate_tx(*args)

    # invalid tx...bob pretending she received coin from alice
    previous_block = deployed_contracts.plasma_instance.functions.getPlasmaCoin(coins[token_uid]).call()[1]
    args = (coins[token_uid], previous_block, 20, bob_addr, bob_addr)
    alice_bob = helpers.utils.generate_tx(*args)

    # plasma block is generated and submited to mainnet
    block_height = next(BLOCK_COUNTER)
    args = (deployed_contracts.plasma_instance, coins[token_uid], alice_bob["tx_hash"], block_height)
    alice_bob["proof"], alice_bob["block_number"] = helpers.utils.generate_block(*args)

    # bob pretending to receive the coin sends it to oscar
    bob_oscar = helpers.utils.generate_tx(
        coins[token_uid],
        alice_bob["block_number"],
        COIN_DENOMINATION,
        oscar_addr,
        bob_addr,
    )

    # plasma block is generated and submited to mainnet
    block_height = next(BLOCK_COUNTER)
    args = (deployed_contracts.plasma_instance, coins[token_uid], bob_oscar["tx_hash"], block_height)
    bob_oscar["proof"], bob_oscar["block_number"] = helpers.utils.generate_block(*args)

    # oscar exits
    w3.personal.unlockAccount(oscar_addr, DEFAULT_PASSWORD)
    events.start_exit(
        deployed_contracts.plasma_instance,
        coins[token_uid],
        alice_bob["tx"],
        bob_oscar["tx"],
        alice_bob["proof"],
        bob_oscar["proof"],
        bob_oscar["signature"],
        [alice_bob["block_number"], bob_oscar["block_number"]],
        oscar_addr
    )

    # alice challenges with his deposit/valid tx.
    helpers.events.challenge_before(
        deployed_contracts.plasma_instance,
        coins[token_uid],
        alice_alice["tx"],
        '0x',
        alice_alice["signature"],
        4,
        alice_addr,
        # since it is a deposit tx from alice the tx_hash is the keccak256 of
        # token uid.
        w3.soliditySha3(['uint64'], [coins[token_uid]])
    )

    helpers.events.finish_challenge_exit(deployed_contracts.plasma_instance, coins[token_uid], alice_addr)
    coin_struct = deployed_contracts.plasma_instance.functions.getPlasmaCoin(coins[token_uid]).call()
    assert coin_struct[4] == 0
Beispiel #11
0
def finish_exit(deployed_contracts, coin_id, address):
    '''
        finishExit calling PlasmaContract finalizeExit function.
        coinI_i : ID of the coin that user wants to finish exit.
        address : address of the user that finishes exit.

        NOTE: gas estimation will not work so we're defaulting to a tad below block size limit
    '''
    # getting the erc20_instance set by deployer.
    erc20_instance = deployed_contracts.erc20_instance
    # getting the erc721_instance set by deployer.
    erc721_instance = deployed_contracts.erc721_instance

    # time required to wait for MATURITY_PERIOD(on mainnet = 1 week / 5 days)
    time.sleep(3)

    """
    Note :
        estimateGas is not working as it should in the case of calling finalizeExit() function.
    """
    args = (coin_id,)
    kwargs = {'from': address, 'gas': BGS_LIMIT}
    w3.personal.unlockAccount(address, DEFAULT_PASSWORD)
    fn_finalized_x = deployed_contracts.plasma_instance.functions.finalizeExit(*args)
    tx_hash = fn_finalized_x.transact(kwargs)
    assert w3.eth.waitForTransactionReceipt(tx_hash).status

    # calling ownerOfToken function on DockPlasmaToken.
    new_owner = erc721_instance.functions.ownerOfToken(coin_id).call()
    assert new_owner == address

    # calling the exit function on PlasmaContract and validate
    exit_struct = deployed_contracts.plasma_instance.functions.getExit(coin_id).call()
    assert exit_struct[0] == '0x0000000000000000000000000000000000000000'
    assert exit_struct[1] == 0
    assert exit_struct[2] == 0
    assert exit_struct[3] == 2

    # calling balances instance of Balance struct on PlasmaContract and validate
    balance = deployed_contracts.plasma_instance.functions.balances(address).call()
    expected = DEFAULT_BOND
    assert balance[0] == 0
    assert balance[1] == expected

    # check gas used
    kwargs = {'from': address}
    w3.personal.unlockAccount(address, DEFAULT_PASSWORD)
    fn_withdraw = deployed_contracts.plasma_instance.functions.withdrawBonds()
    kwargs['gas'] = fn_withdraw.estimateGas(kwargs)
    tx_hash = fn_withdraw.transact(kwargs)
    assert w3.eth.waitForTransactionReceipt(tx_hash).status

    # calling balances instance of Balance struct on PlasmaContract.
    balance = deployed_contracts.plasma_instance.functions.balances(address).call()
    expected = w3.toWei(0, 'ether')
    assert balance[0] == 0
    assert balance[1] == expected

    # validate  balance(s) of ERC20DockToken contract.
    kwargs = {'from': address}
    balanceBefore = erc20_instance.functions.balanceOf(address).call()
    w3.personal.unlockAccount(address, DEFAULT_PASSWORD)
    fn_withdraw = deployed_contracts.plasma_instance.functions.withdraw(coin_id)
    kwargs['gas'] = fn_withdraw.estimateGas(kwargs)
    tx_hash = fn_withdraw.transact(kwargs)
    assert w3.eth.waitForTransactionReceipt(tx_hash).status

    # validate  balance of ERC20DockToken contract.
    balanceAfter = erc20_instance.functions.balanceOf(address).call()
    assert balanceAfter == balanceBefore + COIN_DENOMINATION