Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

A write from a non-authority is refused

Source: record/tests/record.rs L117

  • Given: a record initialized with alice as authority
  • When: setup: payer initializes the record
  • When: mallory tries to forge a write
  • Then: a write from someone who is not the authority is rejected ✓

Result: ✗ failed — 833 CU · claims 1/1 ✓

sequenceDiagram
    participant p0 as mallory
    participant p1 as Record
    p0->>p1: write
    activate p1
    note over p1: 🚩 custom program error  0x0
    p1-->>p0: ✗ 833cu
    deactivate p1

Authority

flowchart LR
    Record["Record"]:::program
    111J[("111J…")]:::state
    mallory(["mallory"]):::signer
    Record -->|writes| 111J
    mallory -->|signs| Record
    classDef program fill:#dae8fc,stroke:#6c8ebf;
    classDef signer fill:#d5e8d4,stroke:#82b366;
    classDef state fill:#ffe6cc,stroke:#d79b00;

Ownership

flowchart LR
    Record["Record"]:::program
    111J[("111J…")]:::state
    system["system"]:::program
    mallory[("mallory")]:::state
    Record -->|owns| 111J
    system -->|owns| mallory
    classDef program fill:#dae8fc,stroke:#6c8ebf;
    classDef signer fill:#d5e8d4,stroke:#82b366;
    classDef state fill:#ffe6cc,stroke:#d79b00;

Accounts

AccountSignerWritableOwner
111J…·Record
mallorysystem
Call tree and logs
A write from a non-authority is refused
mallory (833cu)
└─ Record::write ✗ 833cu
Program recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5 invoke [1]
Program log: RecordInstruction::Write
Program log: Incorrect record authority provided
Program recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5 consumed 833 of 200000 compute units
Program recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5 failed: custom program error: 0x0

Integration

What an integrator writes: the derivations and the instruction, byte-identical to the transaction this page witnessed. Addresses are this scenario’s; supply your own.

#![allow(unused)]
fn main() {
use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::{pubkey, Pubkey};

// --- write ---
let program_id: Pubkey = pubkey!("recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5");
let record_account: Pubkey = pubkey!("111JV6iBiRLoJUtNieRJ9QmcpE2KPE3gLpDzAUkbNW"); // supply your own
let authority: Pubkey = pubkey!("CccbLj76vNwYe3sSTuPVUc1nRqRFG6fhAQThsiochKMg"); // mallory: this scenario's value; supply your own
let ix = Instruction {
    program_id,
    accounts: vec![
        AccountMeta::new(record_account, false), // recordAccount
        AccountMeta::new_readonly(authority, true), // authority
    ],
    // discriminator ++ borsh(offset: 0, data: …)
    data: vec![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x64],
};
}

The same call through the Codama-generated TypeScript client (the async builder derives every PDA the resolver derived here, so only the free inputs appear):

import { address } from "@solana/kit";
import { getWriteInstructionAsync } from "your-generated-client";

const ix = await getWriteInstructionAsync({
  recordAccount: address("111JV6iBiRLoJUtNieRJ9QmcpE2KPE3gLpDzAUkbNW"),
  authority: authoritySigner, // mallory (a TransactionSigner)
  offset: 0n,
  data: /* … */,
});
How this page verifies itself: the test that ran it

The narrative above is this test; the page and the code cannot drift.

#![allow(unused)]
fn main() {
#[test]
fn write_requires_the_authority() {
    let mut story = Story::load(SO, IDL);

    story.given("a record initialized with alice as authority");
    let payer = story.cast("payer");
    let alice = story.cast("alice");
    let mallory = story.cast("mallory");
    let record = story.stage_record(WRITABLE_START + 16);
    story
        .when(
            "setup: payer initializes the record",
            initialize()
                .record_account(record)
                .authority(alice.pubkey()),
            &[&payer],
        )
        .expect_success();

    let out = story.when(
        "mallory tries to forge a write",
        write()
            .record_account(record)
            .authority(&mallory)
            .offset(0)
            .data(b"forged".to_vec()),
        &[&mallory],
    );
    story.then_holds(
        "a write from someone who is not the authority is rejected",
        !out.success,
    );
    emit_scenario(&story, &out, "A write from a non-authority is refused");
}
}