예제 #1
0
    def test_transaction_invalid_accounts(self):
        keys = generate_keys(2)
        tx = Transaction.new(
            keys[0].public_key,
            [Instruction(
                keys[1].public_key,
                bytes([1, 2, 3]),
                [
                    AccountMeta.new(keys[0].public_key, True)
                ],
            )],
        )
        tx.message.instructions[0].program_index = 2  # invalid index
        with pytest.raises(ValueError):
            Transaction.unmarshal(tx.marshal())

        tx = Transaction.new(
            keys[0].public_key,
            [Instruction(
                keys[1].public_key,
                bytes([1, 2, 3]),
                [
                    AccountMeta.new(keys[0].public_key, True)
                ],
            )],
        )
        tx.message.instructions[0].accounts = bytes([2])  # invalid index
        with pytest.raises(ValueError):
            Transaction.unmarshal(tx.marshal())
예제 #2
0
    def test_create_associated_account(self):
        keys = [key.public_key for key in generate_keys(3)]

        expected_addr = get_associated_account(keys[1], keys[2])

        instruction, addr = create_associated_token_account(
            keys[0], keys[1], keys[2])
        assert addr == expected_addr

        assert len(instruction.data) == 0
        assert len(instruction.accounts) == 7

        assert instruction.accounts[0].is_signer
        assert instruction.accounts[0].is_writable
        assert not instruction.accounts[1].is_signer
        assert instruction.accounts[1].is_writable

        for i in range(2, len(instruction.accounts)):
            assert not instruction.accounts[i].is_signer
            assert not instruction.accounts[i].is_writable

        assert instruction.accounts[4].public_key == system.PROGRAM_KEY
        assert instruction.accounts[5].public_key == PROGRAM_KEY
        assert instruction.accounts[6].public_key == system.RENT_SYS_VAR

        tx = Transaction.unmarshal(
            Transaction.new(keys[0], [instruction]).marshal())
        decompiled = decompile_create_associated_account(tx.message, 0)
        assert decompiled.subsidizer == keys[0]
        assert decompiled.owner == keys[1]
        assert decompiled.mint == keys[2]
예제 #3
0
    def test_memo_progam(self):
        data = 'somedata'
        i = memo_instruction(data)

        assert i.data.decode('utf-8') == data

        tx = Transaction.unmarshal(Transaction.new(PublicKey(bytes(32)), [i]).marshal())
        memo = decompile_memo(tx.message, 0)
        assert memo.data.decode('utf-8') == data
예제 #4
0
    def test_transaction_duplicate_keys(self):
        payer, program = generate_keys(2)
        keys = generate_keys(4)
        data = bytes([1, 2, 3])

        # Key[0]: ReadOnlySigner -> WritableSigner
        # Key[1]: ReadOnly       -> ReadOnlySigner
        # Key[2]: Writable       -> Writable       (ReadOnly,noop)
        # Key[3]: WritableSigner -> WritableSigner (ReadOnly,noop)

        tx = Transaction.new(
            payer.public_key,
            [
                Instruction(
                    program.public_key,
                    data,
                    [
                        AccountMeta.new_read_only(keys[0].public_key, True),  # 0 ReadOnlySigner
                        AccountMeta.new_read_only(keys[1].public_key, False),  # 1 ReadOnly
                        AccountMeta.new(keys[2].public_key, False),  # Writable
                        AccountMeta.new(keys[3].public_key, True),  # WritableSigner
                        # Upgrade keys [0] and [1]
                        AccountMeta.new(keys[0].public_key, False),  # Writable (promote to WritableSigner)
                        AccountMeta.new_read_only(keys[1].public_key, True),  # Signer (promote to ReadOnlySigner)
                        # 'Downgrade' keys [2] and [3] (should be noop)
                        AccountMeta.new_read_only(keys[2].public_key, False),  # ReadOnly; still Writable
                        AccountMeta.new_read_only(keys[3].public_key, False)  # Readonly; still a WritableSigner
                    ],
                ),
            ]
        )

        # Intentionally sign out of order to ensure ordering is fixed
        tx.sign([keys[0], keys[1], keys[3], payer])

        assert len(tx.signatures) == 4
        assert len(tx.message.accounts) == 6
        assert tx.message.header.num_signatures == 3
        assert tx.message.header.num_read_only_signed == 1
        assert tx.message.header.num_read_only == 1

        message = tx.message.marshal()
        for idx, key in enumerate([payer, keys[0], keys[3], keys[1]]):
            assert key.public_key.verify(message, tx.signatures[idx])

        expected_keys = [payer, keys[0], keys[3], keys[1], keys[2], program]
        for idx, account in enumerate(expected_keys):
            assert tx.message.accounts[idx] == account.public_key

        assert tx.message.instructions[0].program_index == 5
        assert tx.message.instructions[0].data == data
        assert tx.message.instructions[0].accounts == bytes([1, 3, 4, 2, 1, 3, 4, 2])
예제 #5
0
 def test_transaction_missing_blockhash(self):
     payer, program = generate_keys(2)
     tx = Transaction.new(
         payer.public_key,
         [Instruction(
             program.public_key,
             bytes([1, 2, 3]),
             [
                 AccountMeta.new(payer.public_key, True),
             ],
         )],
     )
     assert Transaction.unmarshal(tx.marshal()) == tx
예제 #6
0
    def test_set_authority(self):
        public_keys = [key.public_key for key in generate_keys(3)]

        # With no new authority
        instruction = set_authority(public_keys[0], public_keys[1], AuthorityType.AccountHolder, _token_program)

        assert instruction.data[0] == Command.SET_AUTHORITY
        assert instruction.data[1] == AuthorityType.AccountHolder
        assert instruction.data[2] == 0

        tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal())
        decompiled = decompile_set_authority(tx.message, 0, _token_program)
        assert decompiled.account == public_keys[0]
        assert decompiled.current_authority == public_keys[1]
        assert decompiled.authority_type == AuthorityType.AccountHolder
        assert not decompiled.new_authority

        # With new authority
        instruction = set_authority(public_keys[0], public_keys[1], AuthorityType.CloseAccount, _token_program,
                                    new_authority=public_keys[2])

        assert instruction.data[0] == Command.SET_AUTHORITY
        assert instruction.data[1] == AuthorityType.CloseAccount
        assert instruction.data[2] == 1
        assert instruction.data[3:] == public_keys[2].raw

        assert not instruction.accounts[0].is_signer
        assert instruction.accounts[0].is_writable
        assert instruction.accounts[1].is_signer
        assert not instruction.accounts[1].is_writable

        tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal())
        decompiled = decompile_set_authority(tx.message, 0, _token_program)
        assert decompiled.account == public_keys[0]
        assert decompiled.current_authority == public_keys[1]
        assert decompiled.authority_type == AuthorityType.CloseAccount
        assert decompiled.new_authority == public_keys[2]
예제 #7
0
    def test_initialize_account(self):
        public_keys = [key.public_key for key in generate_keys(3)]
        instruction = initialize_account(public_keys[0], public_keys[1], public_keys[2], _token_program)

        assert instruction.data == bytes([Command.INITIALIZE_ACCOUNT])
        assert instruction.accounts[0].is_signer
        assert instruction.accounts[0].is_writable
        for i in range(1, 4):
            assert not instruction.accounts[i].is_signer
            assert not instruction.accounts[i].is_writable

        tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal())
        decompiled = decompile_initialize_account(tx.message, 0, _token_program)
        assert decompiled.account == public_keys[0]
        assert decompiled.mint == public_keys[1]
        assert decompiled.owner == public_keys[2]
예제 #8
0
    def test_create_account(self):
        public_keys = [key.public_key for key in generate_keys(3)]
        instruction = create_account(public_keys[0], public_keys[1],
                                     public_keys[2], 12345, 67890)

        assert len(instruction.data) == 52
        assert instruction.data[0:4] == Command.CREATE_ACCOUNT.to_bytes(
            4, 'little')
        assert instruction.data[4:12] == (12345).to_bytes(8, 'little')
        assert instruction.data[12:20] == (67890).to_bytes(8, 'little')
        assert instruction.data[20:] == public_keys[2].raw

        tx = Transaction.unmarshal(
            Transaction.new(public_keys[0], [instruction]).marshal())
        decompiled = decompile_create_account(tx.message, 0)
        assert decompiled.funder == public_keys[0]
        assert decompiled.address == public_keys[1]
        assert decompiled.owner == public_keys[2]
        assert decompiled.lamports == 12345
        assert decompiled.size == 67890
예제 #9
0
    def test_transfer(self):
        public_keys = [key.public_key for key in generate_keys(3)]
        instruction = transfer(public_keys[0], public_keys[1], public_keys[2], 123456789, _token_program)

        assert instruction.data[0] == Command.TRANSFER
        assert instruction.data[1:] == (123456789).to_bytes(8, 'little')

        assert not instruction.accounts[0].is_signer
        assert instruction.accounts[0].is_writable
        assert not instruction.accounts[1].is_signer
        assert instruction.accounts[1].is_writable
        assert instruction.accounts[2].is_signer
        assert instruction.accounts[2].is_writable

        tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal())
        decompiled = decompile_transfer(tx.message, 0, _token_program)
        assert decompiled.source == public_keys[0]
        assert decompiled.dest == public_keys[1]
        assert decompiled.owner == public_keys[2]
        assert decompiled.amount == 123456789
예제 #10
0
    def test_transaction_single_instruction(self):
        payer, program = generate_keys(2)
        keys = generate_keys(4)
        data = bytes([1, 2, 3])

        tx = Transaction.new(
            payer.public_key,
            [Instruction(
                program.public_key,
                data,
                [
                    AccountMeta.new_read_only(keys[0].public_key, True),
                    AccountMeta.new_read_only(keys[1].public_key, False),
                    AccountMeta.new(keys[2].public_key, False),
                    AccountMeta.new(keys[3].public_key, True),
                ],
            )],
        )

        tx.sign([keys[0], keys[3], payer])

        assert len(tx.signatures) == 3
        assert len(tx.message.accounts) == 6
        assert tx.message.header.num_signatures == 2
        assert tx.message.header.num_read_only_signed == 1
        assert tx.message.header.num_read_only == 2

        message = tx.message.marshal()

        assert payer.public_key.verify(message, tx.signatures[0])
        assert keys[3].public_key.verify(message, tx.signatures[1])
        assert keys[0].public_key.verify(message, tx.signatures[2])

        expected_keys = [payer, keys[3], keys[0], keys[2], keys[1], program]
        for idx, key in enumerate(expected_keys):
            assert tx.message.accounts[idx] == key.public_key

        assert tx.message.instructions[0].program_index == 5
        assert tx.message.instructions[0].data == data
        assert tx.message.instructions[0].accounts == bytes([2, 4, 3, 1])
예제 #11
0
    def test_transaction_cross_impl(self):
        pk = PrivateKey(bytes([48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 255, 101, 36, 24, 124, 23,
                               167, 21, 132, 204, 155, 5, 185, 58, 121, 75]))
        program_id = PublicKey(bytes([2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6,
                                      5, 4, 2, 2, 2]))
        to = PublicKey(bytes([1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1,
                              1, 1]))

        tx = Transaction.new(
            pk.public_key,
            [
                Instruction(
                    program_id,
                    bytes([1, 2, 3]),
                    [AccountMeta.new(pk.public_key, True), AccountMeta.new(to, False)],
                ),
            ],
        )
        tx.sign([pk])

        generated = base64.b64decode(_RUST_GENERATED_ADJUSTED)
        assert tx.marshal() == generated
        assert Transaction.unmarshal(generated) == tx
예제 #12
0
    def test_transaction_multi_instruction(self):
        payer, program, program2 = generate_keys(3)
        keys = generate_keys(6)

        data = bytes([1, 2, 3])
        data2 = bytes([3, 4, 5])

        # Key[0]: ReadOnlySigner -> WritableSigner
        # Key[1]: ReadOnly       -> WritableSigner
        # Key[2]: Writable       -> Writable(ReadOnly, noop)
        # Key[3]: WritableSigner -> WritableSigner(ReadOnly, noop)
        # Key[4]: n / a            -> WritableSigner
        # Key[5]: n / a            -> ReadOnly

        tx = Transaction.new(
            payer.public_key,
            [
                Instruction(
                    program.public_key,
                    data,
                    [
                        AccountMeta.new_read_only(keys[0].public_key, True),  # ReadOnlySigner
                        AccountMeta.new_read_only(keys[1].public_key, False),  # ReadOnly
                        AccountMeta.new(keys[2].public_key, False),  # Writable
                        AccountMeta.new(keys[3].public_key, True),  # WritableSigner
                    ],
                ),
                Instruction(
                    program2.public_key,
                    data2,
                    [
                        # Ensure keys don't get downgraded in permissions
                        AccountMeta.new_read_only(keys[3].public_key, False),  # ReadOnly, still WriteableSigner
                        AccountMeta.new_read_only(keys[2].public_key, False),  # ReadOnly, still Writable
                        # Ensure upgrading works
                        AccountMeta.new(keys[0].public_key, False),  # Writable (promote to WritableSigner)
                        AccountMeta.new(keys[1].public_key, True),  # WritableSigner (promote to WritableSigner)
                        # Ensure other accounts get added
                        AccountMeta.new(keys[4].public_key, True),  # WritableSigner
                        AccountMeta.new_read_only(keys[5].public_key, False),  # ReadOnly
                    ],
                ),
            ]
        )

        tx.sign([payer, keys[0], keys[1], keys[3], keys[4]])

        assert len(tx.signatures) == 5
        assert len(tx.message.accounts) == 9
        assert tx.message.header.num_signatures == 5
        assert tx.message.header.num_read_only_signed == 0
        assert tx.message.header.num_read_only == 3

        message = tx.message.marshal()
        for idx, key in enumerate([payer, keys[0], keys[1], keys[3], keys[4]]):
            assert key.public_key.verify(message, tx.signatures[idx])

        expected_keys = [payer, keys[0], keys[1], keys[3], keys[4], keys[2], keys[5], program, program2]
        for idx, account in enumerate(expected_keys):
            assert tx.message.accounts[idx] == account.public_key

        assert tx.message.instructions[0].program_index == 7
        assert tx.message.instructions[0].data == data
        assert tx.message.instructions[0].accounts == bytes([1, 2, 5, 3])

        assert tx.message.instructions[1].program_index == 8
        assert tx.message.instructions[1].data == data2
        assert tx.message.instructions[1].accounts == bytes([3, 5, 1, 2, 4, 6])