def test_challenge_standard_exit_wrong_oindex_should_fail(testlang):
    from plasma_core.utils.transactions import decode_utxo_id, encode_utxo_id
    from plasma_core.transaction import Transaction
    alice, bob, alice_money, bob_money = testlang.accounts[
        0], testlang.accounts[1], 10, 90

    deposit_id = testlang.deposit(alice, alice_money + bob_money)
    deposit_blknum, _, _ = decode_utxo_id(deposit_id)

    spend_tx = Transaction(inputs=[decode_utxo_id(deposit_id)],
                           outputs=[(alice.address, NULL_ADDRESS, alice_money),
                                    (bob.address, NULL_ADDRESS, bob_money)])
    spend_tx.sign(0, alice.key)
    blknum = testlang.submit_block([spend_tx])
    alice_utxo = encode_utxo_id(blknum, 0, 0)
    bob_utxo = encode_utxo_id(blknum, 0, 1)

    testlang.start_standard_exit(alice_utxo, alice.key)

    bob_spend_id = testlang.spend_utxo([bob_utxo], [bob.key],
                                       outputs=[(bob.address, NULL_ADDRESS,
                                                 bob_money)])
    alice_spend_id = testlang.spend_utxo([alice_utxo], [alice.key],
                                         outputs=[(alice.address, NULL_ADDRESS,
                                                   alice_money)])

    with pytest.raises(TransactionFailed):
        testlang.challenge_standard_exit(alice_utxo, bob_spend_id)

    testlang.challenge_standard_exit(alice_utxo, alice_spend_id)
    def transfer(self,
                 input1, newowner1, amount1, signatory1,
                 input2=0, newowner2=None, amount2=0, signatory2=None, cur12=NULL_ADDRESS):
        newowner_address1 = newowner1['address']
        newowner_address2 = NULL_ADDRESS
        if newowner2 is not None:
            newowner_address2 = newowner2['address']

        tx = Transaction(*decode_utxo_id(input1),
                         *decode_utxo_id(input2),
                         cur12,
                         newowner_address1, amount1,
                         newowner_address2, amount2)

        if signatory1 is not None:
            key1 = signatory1['key']
            tx.sign1(key1)

        if signatory2 is not None:
            key2 = signatory2['key']
            tx.sign2(key2)

        spend_id = self.child_chain.apply_transaction(tx)
        self.submit_block()
        return spend_id
def test_challenge_standard_exit_wrong_oindex_should_fail(testlang):
    from plasma_core.utils.transactions import decode_utxo_id, encode_utxo_id
    from plasma_core.transaction import Transaction
    alice, bob, alice_money, bob_money = testlang.accounts[0], testlang.accounts[1], 10, 90

    deposit_id = testlang.deposit(alice, alice_money + bob_money)
    deposit_blknum, _, _ = decode_utxo_id(deposit_id)

    utxo = testlang.child_chain.get_transaction(deposit_id)
    spend_tx = Transaction(*decode_utxo_id(deposit_id),
                           0, 0, 0,
                           utxo.cur12,
                           alice.address, alice_money,
                           bob.address, bob_money)
    spend_tx.sign1(alice.key)
    blknum = testlang.submit_block([spend_tx])
    alice_utxo = encode_utxo_id(blknum, 0, 0)
    bob_utxo = encode_utxo_id(blknum, 0, 1)

    testlang.start_standard_exit(alice, alice_utxo)

    bob_spend_id = testlang.spend_utxo(bob_utxo, bob, bob_money, bob)
    alice_spend_id = testlang.spend_utxo(alice_utxo, alice, alice_money, alice)

    with pytest.raises(TransactionFailed):
        testlang.challenge_standard_exit(alice_utxo, bob_spend_id)

    testlang.challenge_standard_exit(alice_utxo, alice_spend_id)
def test_not_canonial_in_flight_exit_processed_successfully(testlang, plasma_framework):
    owner, deposit_1_amount, deposit_2_amount = testlang.accounts[0], 100, 200
    deposit_id_1 = testlang.deposit(owner, deposit_1_amount)
    deposit_id_2 = testlang.deposit(owner, deposit_2_amount)

    starting_vault_balance = testlang.get_balance(plasma_framework.eth_vault)

    amount_spent = 100
    spend_deposit_2_id = testlang.spend_utxo([deposit_id_2], [owner], outputs=[(owner.address, NULL_ADDRESS, amount_spent)])
    testlang.start_standard_exit(spend_deposit_2_id, account=owner)

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    testlang.process_exits(NULL_ADDRESS, 0, 1)

    vault_balance = testlang.get_balance(plasma_framework.eth_vault)
    assert vault_balance == starting_vault_balance - amount_spent

    # in-flight transaction not included in Plasma
    inputs = [decode_utxo_id(deposit_id_1), decode_utxo_id(deposit_id_2)]
    spend_deposits_tx = Transaction(inputs=inputs, outputs=[(owner.address, NULL_ADDRESS, deposit_2_amount + deposit_1_amount)])
    for i in range(0, len(inputs)):
        spend_deposits_tx.sign(i, owner, verifying_contract=testlang.root_chain.plasma_framework)

    testlang.start_in_flight_exit(None, spend_tx=spend_deposits_tx)
    testlang.piggyback_in_flight_exit_input(None, 0, owner, spend_tx=spend_deposits_tx)
    testlang.challenge_in_flight_exit_not_canonical(None, spend_deposit_2_id, account=owner, in_flight_tx=spend_deposits_tx)

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    testlang.process_exits(NULL_ADDRESS, 0, 1)

    vault_balance = testlang.get_balance(plasma_framework.eth_vault)
    # deposit 1 is withdrawn
    assert vault_balance == starting_vault_balance - amount_spent - deposit_1_amount
def test_finalize_exits_priority_for_in_flight_exits_corresponds_to_the_age_of_youngest_input(testlang):
    owner, amount = testlang.accounts[0], 100
    deposit_0_id = testlang.deposit(owner, amount)
    deposit_1_id = testlang.deposit(owner, amount)

    spend_00_id = testlang.spend_utxo([deposit_0_id], [owner],
                                      [(owner.address, NULL_ADDRESS, 30), (owner.address, NULL_ADDRESS, 70)])
    blknum, txindex, _ = decode_utxo_id(spend_00_id)
    spend_01_id = encode_utxo_id(blknum, txindex, 1)
    spend_1_id = testlang.spend_utxo([spend_01_id], [owner], [(owner.address, NULL_ADDRESS, 70)])
    spend_2_id = testlang.spend_utxo([deposit_1_id], [owner], [(owner.address, NULL_ADDRESS, 100)])

    testlang.start_standard_exit(spend_00_id, owner)

    testlang.start_in_flight_exit(spend_1_id)
    testlang.piggyback_in_flight_exit_output(spend_1_id, 0, owner)
    testlang.start_standard_exit(spend_2_id, owner)

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)

    balance = testlang.get_balance(owner)

    testlang.process_exits(testlang.root_chain.eth_vault_id, NULL_ADDRESS, testlang.get_standard_exit_id(spend_00_id), 1)
    assert testlang.get_balance(owner) == balance + 30 + testlang.root_chain.standardExitBond()

    balance = testlang.get_balance(owner)
    testlang.process_exits(testlang.root_chain.eth_vault_id, NULL_ADDRESS, testlang.get_in_flight_exit_id(spend_1_id), 1)
    assert testlang.get_balance(
        owner) == balance + 70 + testlang.root_chain.inFlightExitBond() + testlang.root_chain.piggybackBond()

    balance = testlang.get_balance(owner)
    testlang.process_exits(testlang.root_chain.eth_vault_id, NULL_ADDRESS, testlang.get_standard_exit_id(spend_2_id), 1)
    assert testlang.get_balance(owner) == balance + 100 + testlang.root_chain.standardExitBond()
def test_piggyback_in_flight_exit_output_with_preexisting_standard_exit_should_fail(
        testlang, num_outputs):
    # exit cross-spend test, case 5
    owner_1, amount = testlang.accounts[0], 100
    deposit_id = testlang.deposit(owner_1, amount)
    outputs = []
    for i in range(0, num_outputs):
        outputs.append((testlang.accounts[i].address, NULL_ADDRESS, 1))
    spend_id = testlang.spend_utxo([deposit_id], [owner_1.key], outputs)

    blknum, txindex, _ = decode_utxo_id(spend_id)
    exit_pos = encode_utxo_id(blknum, txindex, num_outputs - 1)
    testlang.start_standard_exit(exit_pos,
                                 key=testlang.accounts[num_outputs - 1].key)

    testlang.start_in_flight_exit(spend_id)

    assert testlang.get_standard_exit(exit_pos).amount == 1
    bond = testlang.root_chain.piggybackBond()

    with pytest.raises(TransactionFailed):
        testlang.piggyback_in_flight_exit_output(
            spend_id, num_outputs - 1, testlang.accounts[num_outputs - 1].key,
            bond)

    in_flight_exit = testlang.get_in_flight_exit(spend_id)
    assert not in_flight_exit.output_piggybacked(num_outputs - 1)
def test_old_signature_scheme_does_not_work_any_longer(testlang, utxo):
    # In this test I will challenge standard exit with old signature schema to show it no longer works
    # Then passing new signature to the same challenge data, challenge will succeed
    alice = testlang.accounts[0]
    outputs = [(alice.address, NULL_ADDRESS, 50)]
    spend_id = testlang.spend_utxo([utxo.spend_id], [alice], outputs)

    testlang.start_standard_exit(spend_id, alice)
    exit_id = testlang.get_standard_exit_id(spend_id)

    # let's prepare old schema signature for a transaction with an input of exited utxo
    spend_tx = Transaction(inputs=[decode_utxo_id(spend_id)], outputs=outputs)
    old_signature = alice.key.sign_msg_hash(spend_tx.hash).to_bytes()

    # challenge will fail on signature verification
    with pytest.raises(TransactionFailed):
        testlang.root_chain.challengeStandardExit(exit_id, spend_tx.encoded, 0,
                                                  old_signature)

    # sanity check: let's provide new schema signature for a challenge
    new_signature = alice.key.sign_msg_hash(
        hash_struct(spend_tx,
                    verifying_contract=testlang.root_chain)).to_bytes()
    testlang.root_chain.challengeStandardExit(exit_id, spend_tx.encoded, 0,
                                              new_signature)
def test_start_standard_exit_on_in_flight_exit_output_should_block_future_piggybacks(
        testlang, num_outputs):
    # exit cross-spend test, case 7
    owner_1, amount = testlang.accounts[0], 100
    deposit_id = testlang.deposit(owner_1, amount)
    outputs = []
    for i in range(0, num_outputs):
        outputs.append((testlang.accounts[i].address, NULL_ADDRESS, 1))
    spend_id = testlang.spend_utxo([deposit_id], [owner_1], outputs)

    testlang.start_in_flight_exit(spend_id)

    output_index = num_outputs - 1

    blknum, txindex, _ = decode_utxo_id(spend_id)
    output_id = encode_utxo_id(blknum, txindex, output_index)
    testlang.start_standard_exit(output_id,
                                 account=testlang.accounts[output_index])

    with pytest.raises(TransactionFailed):
        testlang.piggyback_in_flight_exit_output(
            spend_id, output_index, testlang.accounts[output_index])

    in_flight_exit = testlang.get_in_flight_exit(spend_id)
    assert not in_flight_exit.output_piggybacked(output_index)
    assert in_flight_exit.output_blocked(output_index)
Exemple #9
0
 def mark_utxo_spent(self, utxo_id):
     (_, _, oindex) = decode_utxo_id(utxo_id)
     tx = self.get_transaction(utxo_id)
     if oindex == 0:
         tx.spent1 = True
     else:
         tx.spent2 = True
def test_output_exited_via_ife_and_then_se_withdraws_once(testlang, plasma_framework, num_outputs):
    owner, amount, amount_spent = testlang.accounts[0], 100, 1
    deposit_id = testlang.deposit(owner, amount)

    outputs = []
    for i in range(0, num_outputs):
        outputs.append((owner.address, NULL_ADDRESS, amount_spent))
    spend_id = testlang.spend_utxo([deposit_id], [owner], outputs)

    output_index = num_outputs - 1

    testlang.start_in_flight_exit(spend_id)

    blknum, txindex, _ = decode_utxo_id(spend_id)
    output_id = encode_utxo_id(blknum, txindex, output_index)

    testlang.piggyback_in_flight_exit_output(spend_id, output_index, owner)
    testlang.start_standard_exit(output_id, account=owner)

    pre_exit_balance = testlang.get_balance(plasma_framework.eth_vault)

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    testlang.process_exits(NULL_ADDRESS, 0, 100)

    post_exit_balance = testlang.get_balance(plasma_framework.eth_vault)
    assert post_exit_balance == pre_exit_balance - amount_spent
def test_start_standard_exit_on_finalized_in_flight_exit_output_should_fail(
        testlang, num_outputs):
    owner, amount = testlang.accounts[0], 100
    deposit_id = testlang.deposit(owner, amount)
    outputs = [(owner.address, NULL_ADDRESS, 1)] * num_outputs
    spend_id = testlang.spend_utxo([deposit_id], [owner], outputs)
    output_index = num_outputs - 1

    # start IFE, piggyback one output and process the exit
    testlang.start_in_flight_exit(spend_id)
    testlang.piggyback_in_flight_exit_output(spend_id, output_index, owner)
    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    testlang.process_exits(testlang.root_chain.eth_vault_id, NULL_ADDRESS, 0,
                           1)

    blknum, txindex, _ = decode_utxo_id(spend_id)

    # all not finalized outputs can exit via SE
    for i in range(output_index):
        output_id = encode_utxo_id(blknum, txindex, i)
        testlang.start_standard_exit(output_id, account=owner)

    # an already finalized output __cannot__ exit via SE
    with pytest.raises(TransactionFailed):
        output_id = encode_utxo_id(blknum, txindex, output_index)
        testlang.start_standard_exit(output_id, account=owner)
Exemple #12
0
def test_challenge_standard_exit_with_in_flight_exit_tx_should_succeed(
        ethtester, testlang):
    # exit cross-spend test, cases 3 and 4
    owner, amount = testlang.accounts[0], 100
    deposit_id = testlang.deposit(owner, amount)
    spend_id = testlang.spend_utxo([deposit_id], [owner.key],
                                   outputs=[(owner.address, NULL_ADDRESS,
                                             amount)])

    ife_tx = Transaction(inputs=[decode_utxo_id(spend_id)],
                         outputs=[(owner.address, NULL_ADDRESS, amount)])
    ife_tx.sign(0, owner.key)

    (encoded_spend, encoded_inputs, proofs,
     signatures) = testlang.get_in_flight_exit_info(None, spend_tx=ife_tx)
    bond = testlang.root_chain.inFlightExitBond()
    testlang.root_chain.startInFlightExit(encoded_spend,
                                          encoded_inputs,
                                          proofs,
                                          signatures,
                                          value=bond,
                                          sender=owner.key)

    testlang.start_standard_exit(spend_id, owner.key)
    assert testlang.get_standard_exit(spend_id).amount == 100

    exit_id = testlang.get_standard_exit_id(spend_id)
    # FIXME a proper way of getting encoded body of IFE tx is to get it out of generated events
    testlang.root_chain.challengeStandardExit(exit_id, ife_tx.encoded, 0,
                                              ife_tx.signatures[0])

    assert testlang.get_standard_exit(spend_id) == [
        NULL_ADDRESS_HEX, NULL_ADDRESS_HEX, 0, 0
    ]
Exemple #13
0
def test_piggyback_in_flight_exit_output_with_preexisting_finalized_standard_exit_should_fail(
        testlang, num_outputs):
    # exit cross-spend test, case 6
    owner, amount = testlang.accounts[0], 100
    deposit_id = testlang.deposit(owner, amount)
    outputs = []
    for i in range(num_outputs):
        outputs.append((testlang.accounts[i].address, NULL_ADDRESS, 1))
    spend_id = testlang.spend_utxo([deposit_id], [owner], outputs)

    blknum, txindex, _ = decode_utxo_id(spend_id)
    exit_pos = encode_utxo_id(blknum, txindex, num_outputs - 1)
    testlang.start_standard_exit(exit_pos,
                                 account=testlang.accounts[num_outputs - 1])

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    testlang.process_exits(NULL_ADDRESS, 0, 1)

    testlang.start_in_flight_exit(spend_id)

    assert testlang.get_standard_exit(exit_pos).amount == 1
    bond = testlang.root_chain.piggybackBond()

    with pytest.raises(TransactionFailed):
        testlang.piggyback_in_flight_exit_output(
            spend_id, num_outputs - 1, testlang.accounts[num_outputs - 1],
            bond)

    in_flight_exit = testlang.get_in_flight_exit(spend_id)
    assert not in_flight_exit.output_piggybacked(num_outputs - 1)
Exemple #14
0
    def spend_utxo(self, utxo_id, new_owner, amount, signer):
        """Creates a spending transaction and inserts it into the chain.

        Args:
            utxo_id (int): Identifier of the UTXO to spend.
            new_owner (EthereumAccount): Account to own the output of this spend.
            amount (int): Amount to spend.
            signer (EthereumAccount): Account to sign this transaction.

        Returns:
            int: Unique identifier of the spend.
        """

        spend_tx = Transaction(*decode_utxo_id(utxo_id),
                               0, 0, 0,
                               NULL_ADDRESS,
                               new_owner.address, amount,
                               NULL_ADDRESS, 0)
        spend_tx.sign1(signer.key)

        blknum = self.root_chain.currentChildBlock()
        block = Block(transaction_set=[spend_tx], number=blknum)
        block.sign(self.operator.key)
        self.root_chain.submitBlock(block.root)
        self.child_chain.add_block(block)
        return encode_utxo_id(blknum, 0, 0)
def test_should_not_allow_to_withdraw_outputs_from_two_ifes_marked_as_canonical_but_sharing_an_input(testlang, plasma_framework, token):
    alice, amount_token = testlang.accounts[0], 200
    caroline, amount_eth = testlang.accounts[1], 100

    deposit_id_token = testlang.deposit_token(alice, token, amount_token)
    deposit_id_eth = testlang.deposit(caroline, amount_eth)

    swap_tx_id = testlang.spend_utxo(
        [deposit_id_token, deposit_id_eth], [alice, caroline], [(alice.address, NULL_ADDRESS, amount_eth), (caroline.address, token.address, amount_token)])

    # in-flight transaction not included in Plasma
    steal_tx = Transaction(inputs=[decode_utxo_id(deposit_id_eth)], outputs=[(caroline.address, NULL_ADDRESS, amount_eth)])
    steal_tx.sign(0, caroline, verifying_contract=testlang.root_chain.plasma_framework)

    testlang.start_in_flight_exit(swap_tx_id)
    testlang.start_in_flight_exit(None, spend_tx=steal_tx)

    caroline_token_balance_before = token.balanceOf(caroline.address)
    caroline_eth_balance_before = testlang.get_balance(caroline)

    testlang.piggyback_in_flight_exit_output(swap_tx_id, 1, caroline)
    testlang.piggyback_in_flight_exit_output(None, 0, caroline, spend_tx=steal_tx)

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    testlang.process_exits(token.address, 0, 1)
    testlang.process_exits(NULL_ADDRESS, 0, 1)

    # caroline exits with the tokens (previously owned by alice)
    caroline_token_balance = token.balanceOf(caroline.address)
    assert caroline_token_balance == caroline_token_balance_before + amount_token

    # but she can not exit with Eth
    caroline_eth_balance = testlang.get_balance(caroline)
    assert caroline_eth_balance == caroline_eth_balance_before
 def spend_utxo(self, input_ids, keys, outputs=[], force_invalid=False):
     inputs = [decode_utxo_id(input_id) for input_id in input_ids]
     spend_tx = Transaction(inputs=inputs, outputs=outputs)
     for i in range(0, len(inputs)):
         spend_tx.sign(i, keys[i])
     blknum = self.submit_block([spend_tx], force_invalid=force_invalid)
     spend_id = encode_utxo_id(blknum, 0, 0)
     return spend_id
    def confirm(self, tx_id, signatory1, signatory2=None):
        tx = self.child_chain.get_transaction(tx_id)
        (blknum, _, _) = decode_utxo_id(tx_id)
        block_root = self.child_chain.get_block(blknum).root

        confirm_sigs = b''
        for signatory in [x for x in [signatory1, signatory2] if x is not None]:
            confirm_sigs += confirm_tx(tx, block_root, signatory['key'])

        self.confirmations[tx_id] = confirm_sigs
Exemple #18
0
def test_token_deposit_should_succeed(testlang, root_chain, token):
    owner, amount = testlang.accounts[0], 100

    deposit_id = testlang.deposit_token(owner, token, amount)
    deposit_blknum, _, _ = decode_utxo_id(deposit_id)

    plasma_block = testlang.get_plasma_block(deposit_blknum)
    assert plasma_block.root == testlang.child_chain.get_block(deposit_blknum).root
    assert plasma_block.timestamp == testlang.timestamp
    assert root_chain.nextDepositBlock() == 2
def test_should_not_allow_to_withdraw_inputs_and_outputs_when_ifes_processing_interchanges(testlang, plasma_framework, token):
    alice, amount_token = testlang.accounts[0], 200
    caroline, amount_eth = testlang.accounts[1], 100

    deposit_id_token = testlang.deposit_token(alice, token, amount_token)
    deposit_id_eth = testlang.deposit(caroline, amount_eth)

    swap_tx_id = testlang.spend_utxo(
        [deposit_id_token, deposit_id_eth], [alice, caroline], [(alice.address, NULL_ADDRESS, amount_eth), (caroline.address, token.address, amount_token)])

    # in-flight transaction not included in Plasma
    steal_tx = Transaction(inputs=[decode_utxo_id(deposit_id_eth)], outputs=[(caroline.address, NULL_ADDRESS, amount_eth)])
    steal_tx.sign(0, caroline, verifying_contract=testlang.root_chain.plasma_framework)

    alice_token_balance_before = token.balanceOf(alice.address)
    alice_eth_balance_before = testlang.get_balance(alice)
    caroline_token_balance_before = token.balanceOf(caroline.address)
    caroline_eth_balance_before = testlang.get_balance(caroline)

    testlang.start_in_flight_exit(swap_tx_id)
    testlang.start_in_flight_exit(None, spend_tx=steal_tx)

    testlang.piggyback_in_flight_exit_input(swap_tx_id, 0, alice)
    testlang.piggyback_in_flight_exit_input(swap_tx_id, 1, caroline)
    testlang.piggyback_in_flight_exit_output(swap_tx_id, 0, alice)
    testlang.piggyback_in_flight_exit_output(swap_tx_id, 1, caroline)

    # we have encounter flaky tests. we are guessing it is caused by two exits being enqueued in the time that is too close.
    # within same root chain block time span, the priority in the queue could be the same and hard to differentiate.
    # https://github.com/omgnetwork/plasma-contracts/issues/606
    TIME_DIFF_FOR_ENSUREING_EXIT_PRIORITY = 10
    testlang.forward_timestamp(TIME_DIFF_FOR_ENSUREING_EXIT_PRIORITY)

    testlang.piggyback_in_flight_exit_output(None, 0, caroline, spend_tx=steal_tx)
    testlang.piggyback_in_flight_exit_input(None, 0, caroline, spend_tx=steal_tx)

    testlang.forward_timestamp(2 * MIN_EXIT_PERIOD + 1)
    # process swap_tx Eth exit and then steal_tx Eth exit
    testlang.process_exits(NULL_ADDRESS, 0, 2)
    # process token exit
    testlang.process_exits(token.address, 0, 1)

    # caroline exits with the tokens
    caroline_token_balance = token.balanceOf(caroline.address)
    assert caroline_token_balance == caroline_token_balance_before + amount_token
    # but she does not get ETH back
    caroline_eth_balance = testlang.get_balance(caroline)
    assert caroline_eth_balance == caroline_eth_balance_before

    # alice exits with eth
    alice_eth_balance = testlang.get_balance(alice)
    assert alice_eth_balance == alice_eth_balance_before + amount_eth
    # but she does not get token back
    alice_token_balance = token.balanceOf(alice.address)
    assert alice_token_balance == alice_token_balance_before
    def start_exit(self, utxo_id, exitor):
        tx = self.child_chain.get_transaction(utxo_id)

        sigs = tx.sig1 + tx.sig2 + self.confirmations[utxo_id]
        (blknum, _, _) = decode_utxo_id(utxo_id)
        block = self.child_chain.get_block(blknum)
        proof = block.merkle.create_membership_proof(tx.merkle_hash)

        self.root_chain.transact({
            'from': exitor['address']
        }).startExit(utxo_id, tx.encoded, proof, sigs)
def test_token_deposit_should_succeed(testlang, root_chain, token):
    owner, amount = testlang.accounts[0], 100

    deposit_id = testlang.deposit_token(owner, token, amount)
    deposit_blknum, _, _ = decode_utxo_id(deposit_id)

    plasma_block = testlang.get_plasma_block(deposit_blknum)
    assert plasma_block.root == get_deposit_hash(
        address_to_bytes(owner.address), token.address, amount)
    assert plasma_block.timestamp == testlang.timestamp
    assert root_chain.currentDepositBlock() == 2
def test_deposit_valid_values_should_succeed(testlang):
    owner, amount = testlang.accounts[0], 100

    deposit_id = testlang.deposit(owner, amount)
    deposit_blknum, _, _ = decode_utxo_id(deposit_id)

    plasma_block = testlang.get_plasma_block(deposit_blknum)
    assert plasma_block.root == get_deposit_hash(
        address_to_bytes(owner.address), NULL_ADDRESS, amount)
    assert plasma_block.timestamp == testlang.timestamp
    assert testlang.root_chain.currentDepositBlock() == 2
Exemple #23
0
 def mark_utxo_spent(self, utxo_id):
     (_, _, oindex) = decode_utxo_id(utxo_id)
     tx = self.get_transaction(utxo_id)
     print("tx {0}".format(tx))
     if not tx:
         print("tx is empty")
         return
     if oindex == 0:
         tx.spent1 = True
     else:
         tx.spent2 = True
Exemple #24
0
def test_start_standard_exit_wrong_oindex_should_fail(testlang):
    alice, bob, alice_money, bob_money = testlang.accounts[0], testlang.accounts[1], 10, 90

    deposit_id = testlang.deposit(alice, alice_money + bob_money)
    deposit_blknum, _, _ = decode_utxo_id(deposit_id)

    spend_tx = Transaction(inputs=[decode_utxo_id(deposit_id)],
                           outputs=[(alice.address, NULL_ADDRESS, alice_money), (bob.address, NULL_ADDRESS, bob_money)])
    spend_tx.sign(0, alice.key, verifyingContract=testlang.root_chain)
    blknum = testlang.submit_block([spend_tx])
    alice_utxo = encode_utxo_id(blknum, 0, 0)
    bob_utxo = encode_utxo_id(blknum, 0, 1)

    with pytest.raises(TransactionFailed):
        testlang.start_standard_exit(bob_utxo, alice.key)

    with pytest.raises(TransactionFailed):
        testlang.start_standard_exit(alice_utxo, bob.key)

    testlang.start_standard_exit(alice_utxo, alice.key)
    testlang.start_standard_exit(bob_utxo, bob.key)
Exemple #25
0
def test_challenge_exit(t, u, root_chain, assert_tx_failed):
    owner, value_1, key = t.a1, 100, t.k1
    tx1 = Transaction(0, 0, 0, 0, 0, 0,
                      NULL_ADDRESS,
                      owner, value_1, NULL_ADDRESS, 0)
    deposit_tx_hash = get_deposit_hash(owner, NULL_ADDRESS, value_1)
    utxo_pos1 = encode_utxo_id(root_chain.getDepositBlock(), 0, 0)
    root_chain.deposit(value=value_1, sender=key)
    utxo_pos2 = encode_utxo_id(root_chain.getDepositBlock(), 0, 0)
    root_chain.deposit(value=value_1, sender=key)
    merkle = FixedMerkle(16, [deposit_tx_hash], True)
    proof = merkle.create_membership_proof(deposit_tx_hash)
    confirmSig1 = confirm_tx(tx1, root_chain.getPlasmaBlock(utxo_pos1)[0], key)
    sigs = tx1.sig1 + tx1.sig2 + confirmSig1
    exit_bond = root_chain.EXIT_BOND()
    root_chain.startDepositExit(utxo_pos1, NULL_ADDRESS, tx1.amount1, sender=key, value=exit_bond)
    tx3 = Transaction(utxo_pos2, 0, 0, 0, 0, 0,
                      NULL_ADDRESS,
                      owner, value_1, NULL_ADDRESS, 0)
    tx3.sign1(key)
    tx_bytes3 = rlp.encode(tx3, UnsignedTransaction)
    merkle = FixedMerkle(16, [tx3.merkle_hash], True)
    proof = merkle.create_membership_proof(tx3.merkle_hash)
    child_blknum = root_chain.currentChildBlock()
    root_chain.submitBlock(merkle.root)
    confirmSig = confirm_tx(tx3, root_chain.getPlasmaBlock(child_blknum)[0], key)
    sigs = tx3.sig1 + tx3.sig2
    utxo_pos3 = encode_utxo_id(child_blknum, 0, 0)

    utxo1_blknum, _, _ = decode_utxo_id(utxo_pos1)
    tx4 = Transaction(utxo1_blknum, 0, 0, 0, 0, 0,
                      NULL_ADDRESS,
                      owner, value_1, NULL_ADDRESS, 0)
    tx4.sign1(key)
    tx_bytes4 = rlp.encode(tx4, UnsignedTransaction)
    merkle = FixedMerkle(16, [tx4.merkle_hash], True)
    proof = merkle.create_membership_proof(tx4.merkle_hash)
    child_blknum = root_chain.currentChildBlock()
    root_chain.submitBlock(merkle.root)
    confirmSig = confirm_tx(tx4, root_chain.getPlasmaBlock(child_blknum)[0], key)
    sigs = tx4.sig1 + tx4.sig2
    utxo_pos4 = encode_utxo_id(child_blknum, 0, 0)
    oindex1 = 0
    assert root_chain.exits(utxo_pos1) == ['0x' + owner.hex(), NULL_ADDRESS_HEX, 100]
    # Fails if transaction after exit doesn't reference the utxo being exited
    assert_tx_failed(lambda: root_chain.challengeExit(utxo_pos3, oindex1, tx_bytes3, proof, sigs, confirmSig))
    # Fails if transaction proof is incorrect
    assert_tx_failed(lambda: root_chain.challengeExit(utxo_pos4, oindex1, tx_bytes4, proof[::-1], sigs, confirmSig))
    # Fails if transaction confirmation is incorrect
    assert_tx_failed(lambda: root_chain.challengeExit(utxo_pos4, oindex1, tx_bytes4, proof, sigs, confirmSig[::-1]))
    root_chain.challengeExit(utxo_pos4, oindex1, tx_bytes4, proof, sigs, confirmSig)
    assert root_chain.exits(utxo_pos1) == [NULL_ADDRESS_HEX, NULL_ADDRESS_HEX, value_1]
Exemple #26
0
    def confirm_spend(self, tx_id, signer):
        """Signs a confirmation signature for a spend.

        Args:
            tx_id (int): Identifier of the transaction.
            signer (EthereumAccount): Account to sign this confirmation.
        """

        spend_tx = self.child_chain.get_transaction(tx_id)
        (blknum, _, _) = decode_utxo_id(tx_id)
        block = self.child_chain.blocks[blknum]
        confirmation_hash = sha3(spend_tx.hash + block.root)
        self.confirmations[tx_id] = sign(confirmation_hash, signer.key)
Exemple #27
0
 def get_transaction(self, utxo_id):
     (blknum, txindex, _) = decode_utxo_id(utxo_id)
     print("blocks {0}".format(self.blocks))
     if not self.blocks:
         print("blocks are empty")
         return {}
     if blknum not in self.blocks:
         print("block num not in dictionary")
         return {}
     if not self.blocks[blknum].transaction_set:
         print("transaction_set is empty")
         return {}
     return self.blocks[blknum].transaction_set[txindex]
def test_metadata_is_part_of_the_proof(testlang):
    owner, amount = testlang.accounts[0], 100
    deposit_id = testlang.deposit(owner, amount)

    input_ids = [deposit_id]
    keys = [owner.key]
    outputs = [(owner.address, NULL_ADDRESS, amount)]
    spend_id = testlang.spend_utxo(input_ids, keys, outputs, "metadata info")

    inputs = [decode_utxo_id(input_id) for input_id in input_ids]
    bad_spend_tx = Transaction(inputs=inputs, outputs=outputs, metadata="other information")
    with pytest.raises(TransactionFailed):
        testlang.start_standard_exit_with_tx_body(spend_id, bad_spend_tx, owner.key)
Exemple #29
0
    def start_exit(self, owner, utxo_id):
        """Starts a standard exit.

        Args:
            owner (EthereumAccount): Account to attempt the exit.
            utxo_id (int): Unique identifier of the UTXO to be exited.
        """

        spend_tx = self.child_chain.get_transaction(utxo_id)
        (blknum, _, _) = decode_utxo_id(utxo_id)
        block = self.child_chain.blocks[blknum]
        proof = block.merkle_tree.create_membership_proof(spend_tx.merkle_hash)
        sigs = spend_tx.sig1 + spend_tx.sig2 + self.confirmations[utxo_id]
        self.root_chain.startExit(utxo_id, spend_tx.encoded, proof, sigs, sender=owner.key)
Exemple #30
0
    def get_challenge_proof(self, utxo_id, spend_id):
        """Returns information required to submit a challenge.

        Args:
            utxo_id (int): Identifier of the UTXO being exited.
            spend_id (int): Identifier of the transaction that spent the UTXO.

        Returns:
            int, bytes, bytes, bytes, bytes: Information necessary to create a challenge proof.
        """

        spend_tx = self.child_chain.get_transaction(spend_id)
        inputs = [(spend_tx.blknum1, spend_tx.txindex1, spend_tx.oindex1), (spend_tx.blknum2, spend_tx.txindex2, spend_tx.oindex2)]
        try:
            input_index = inputs.index(decode_utxo_id(utxo_id))
        except ValueError:
            input_index = 0
        (blknum, _, _) = decode_utxo_id(spend_id)
        block = self.child_chain.blocks[blknum]
        proof = block.merkle_tree.create_membership_proof(spend_tx.merkle_hash)
        sigs = spend_tx.sig1 + spend_tx.sig2
        confirmation_sig = self.confirmations[spend_id]
        return (input_index, spend_tx.encoded, proof, sigs, confirmation_sig)