Example #1
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])
Example #2
0
def close_account(account: PublicKey, dest: PublicKey,
                  owner: PublicKey) -> Instruction:
    return Instruction(PROGRAM_KEY, bytes([Command.CLOSE_ACCOUNT]), [
        AccountMeta.new(account, False),
        AccountMeta.new(dest, False),
        AccountMeta.new_read_only(owner, True),
    ])
Example #3
0
def initialize_account(account: PublicKey, mint: PublicKey,
                       owner: PublicKey) -> Instruction:
    """
    // Accounts expected by this instruction:
    //
    //   0. `[writable]`  The account to initialize.
    //   1. `[]` The mint this account will be associated with.
    //   2. `[]` The new account's owner/multisignature.
    //   3. `[]` Rent sysvar

    :return:
    """

    return Instruction(PROGRAM_KEY, bytes([Command.INITIALIZE_ACCOUNT]), [
        AccountMeta.new(account, False),
        AccountMeta.new_read_only(mint, False),
        AccountMeta.new_read_only(owner, False),
        AccountMeta.new_read_only(system.RENT_SYS_VAR, False),
    ])
Example #4
0
def create_associated_token_account(
    subsidizer: PublicKey,
    wallet: PublicKey,
    mint: PublicKey,
) -> Tuple[Instruction, PublicKey]:
    addr = get_associated_account(wallet, mint)
    return Instruction(
        ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_KEY,
        bytes(),
        [
            AccountMeta.new(subsidizer, True),
            AccountMeta.new(addr, False),
            AccountMeta.new_read_only(wallet, False),
            AccountMeta.new_read_only(mint, False),
            AccountMeta.new_read_only(system.PROGRAM_KEY, False),
            AccountMeta.new_read_only(PROGRAM_KEY, False),
            AccountMeta.new_read_only(system.RENT_SYS_VAR, False),
        ],
    ), addr
Example #5
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])
Example #6
0
def set_authority(account: PublicKey,
                  current_authority: PublicKey,
                  authority_type: AuthorityType,
                  new_authority: Optional[PublicKey] = None) -> Instruction:
    data = bytearray([Command.SET_AUTHORITY, authority_type])
    if not new_authority:
        data.append(0)
    else:
        data.append(1)
        data.extend(new_authority.raw)

    return Instruction(PROGRAM_KEY, data, [
        AccountMeta.new(account, False),
        AccountMeta.new_read_only(current_authority, True),
    ])
Example #7
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])