Skip to content

Commit 79a60e0

Browse files
added tests
1 parent 17d82f2 commit 79a60e0

File tree

4 files changed

+181
-15
lines changed

4 files changed

+181
-15
lines changed
Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
# ProgramDerivedAddresses
1+
# Program Derived Addresses
22

3-
**ProgramDerivedAddresses** is a ...
4-
5-
## API
6-
- [`Consts`](api/src/consts.rs) – Program constants.
7-
- [`Error`](api/src/error.rs) – Custom program errors.
8-
- [`Event`](api/src/event.rs) – Custom program events.
9-
- [`Instruction`](api/src/instruction.rs) – Declared instructions.
3+
This program demonstrates how to derive addresses. It will use a PDA to store a counter of visits and increment it.
104

11-
## Instructions
12-
- [`Hello`](program/src/hello.rs) – Hello ...
5+
## Building
136

14-
## State
15-
- [`User`](api/src/state/user.rs) – User ...
7+
```sh
8+
cargo build-sbf
169

10+
```
1711
## Tests
1812

19-
To run the test suit, use the Solana toolchain:
20-
```
21-
cargo test-sbf
13+
This project includes both:
14+
- Rust tests: [`program/tests`](/program/tests) directory.
15+
- Node.js tests using [Bankrun](https://kevinheavey.github.io/solana-bankrun/): [`tests`](/tests) directory.
16+
17+
```sh
18+
# rust tests
19+
cargo test-sbf
20+
21+
# node tests
22+
pnpm build-and-test # this will also build the program
23+
#or
24+
pnpm test # if you have already built the program
2225
```

basics/program-derived-addresses/steel/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@types/chai": "^4.3.7",
1919
"@types/mocha": "10.0.9",
2020
"@types/node": "^22.7.4",
21+
"borsh": "^2.0.0",
2122
"chai": "^4.3.7",
2223
"mocha": "10.7.3",
2324
"solana-bankrun": "0.4.0",

basics/program-derived-addresses/steel/pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
2+
import * as borsh from 'borsh';
3+
import { assert } from 'chai';
4+
import { describe, it } from 'mocha';
5+
import { BanksClient, ProgramTestContext, start } from 'solana-bankrun';
6+
7+
type PageVisits = {
8+
page_visits: number;
9+
bump: number;
10+
};
11+
12+
const pageVisitsSchema: borsh.Schema = {
13+
struct: {
14+
discriminator: 'u64',
15+
page_visits: 'u32',
16+
bump: 'u8',
17+
},
18+
};
19+
20+
const createPageVisitsBuffer = (data: PageVisits): Buffer => {
21+
const pageVisits = Buffer.alloc(4);
22+
pageVisits.writeUInt32LE(data.page_visits, 0);
23+
const bump = Buffer.alloc(1);
24+
bump.writeUInt8(data.bump, 0);
25+
return Buffer.concat([pageVisits, bump]);
26+
};
27+
28+
describe('program derived addresses program', async () => {
29+
const PROGRAM_ID = new PublicKey('z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35');
30+
31+
let context: ProgramTestContext;
32+
let client: BanksClient;
33+
let payer: Keypair;
34+
35+
const testUser = Keypair.generate();
36+
37+
const instructionDiscriminators = {
38+
create: Buffer.from([0]),
39+
increment: Buffer.from([1]),
40+
};
41+
42+
const derivePageVisitsPDA = async (user: PublicKey) => {
43+
const seed = Buffer.from('program-derived-addresses');
44+
return PublicKey.findProgramAddressSync([seed, user.toBuffer()], PROGRAM_ID);
45+
};
46+
47+
before(async () => {
48+
context = await start([{ name: 'program_derived_addresses_program', programId: PROGRAM_ID }], []);
49+
client = context.banksClient;
50+
payer = context.payer;
51+
});
52+
53+
it('should create a page visits tracking PDA', async () => {
54+
const [pageVisitsPDA] = await derivePageVisitsPDA(testUser.publicKey);
55+
56+
// create the page visits data
57+
const pageVisits: PageVisits = { page_visits: 0, bump: 0 };
58+
const pageVisitsBuffer = createPageVisitsBuffer(pageVisits);
59+
const data = Buffer.concat([instructionDiscriminators.create, pageVisitsBuffer]);
60+
61+
// create the create instruction
62+
const createIx = new TransactionInstruction({
63+
programId: PROGRAM_ID,
64+
keys: [
65+
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
66+
{ pubkey: testUser.publicKey, isSigner: false, isWritable: false },
67+
{ pubkey: pageVisitsPDA, isSigner: false, isWritable: true },
68+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
69+
],
70+
data,
71+
});
72+
73+
// send the create transaction
74+
const createTx = new Transaction();
75+
createTx.recentBlockhash = context.lastBlockhash;
76+
createTx.add(createIx).sign(payer);
77+
78+
// process the transaction
79+
await client.processTransaction(createTx);
80+
81+
// fetch the counter account data
82+
const pageVisitsInfo = await client.getAccount(pageVisitsPDA);
83+
assert(pageVisitsInfo !== null, 'account should exist');
84+
});
85+
86+
it('should visit the page and get 1 visit!', async () => {
87+
const [pageVisitsPDA] = await derivePageVisitsPDA(testUser.publicKey);
88+
89+
// create the increment instruction
90+
const incrementIx = new TransactionInstruction({
91+
programId: PROGRAM_ID,
92+
keys: [{ pubkey: pageVisitsPDA, isSigner: false, isWritable: true }],
93+
data: instructionDiscriminators.increment,
94+
});
95+
96+
// send the increment transaction
97+
const incrementTx = new Transaction();
98+
incrementTx.recentBlockhash = context.lastBlockhash;
99+
incrementTx.add(incrementIx).sign(payer);
100+
101+
// process the transaction
102+
await client.processTransaction(incrementTx);
103+
104+
// fetch the account data
105+
const pageVisitsInfo = await client.getAccount(pageVisitsPDA);
106+
assert(pageVisitsInfo !== null, 'account should exist');
107+
108+
const data = borsh.deserialize(pageVisitsSchema, pageVisitsInfo?.data) as PageVisits;
109+
110+
assert(data.page_visits === 1, 'page visits should be 1');
111+
});
112+
113+
it('should visit the page and get 2 visits!', async () => {
114+
const [pageVisitsPDA] = await derivePageVisitsPDA(testUser.publicKey);
115+
116+
// create the increment instruction
117+
const incrementIx = new TransactionInstruction({
118+
programId: PROGRAM_ID,
119+
keys: [{ pubkey: pageVisitsPDA, isSigner: false, isWritable: true }],
120+
data: instructionDiscriminators.increment,
121+
});
122+
123+
// get last blockhash
124+
const [blockhash, _block_height] = await client.getLatestBlockhash();
125+
126+
// send the increment transaction
127+
const incrementTx = new Transaction();
128+
incrementTx.recentBlockhash = blockhash;
129+
incrementTx.add(incrementIx).sign(payer);
130+
131+
// process the transaction
132+
await client.processTransaction(incrementTx);
133+
134+
// fetch the account data
135+
const pageVisitsInfo = await client.getAccount(pageVisitsPDA);
136+
assert(pageVisitsInfo !== null, 'account should exist');
137+
138+
const data = borsh.deserialize(pageVisitsSchema, pageVisitsInfo?.data) as PageVisits;
139+
140+
assert(data.page_visits === 2, 'page visits should be 2');
141+
});
142+
143+
it('should read all the visits of the page', async () => {
144+
const [pageVisitsPDA] = await derivePageVisitsPDA(testUser.publicKey);
145+
146+
// fetch the account data
147+
const pageVisitsInfo = await client.getAccount(pageVisitsPDA);
148+
assert(pageVisitsInfo !== null, 'account should exist');
149+
150+
const data = borsh.deserialize(pageVisitsSchema, pageVisitsInfo?.data) as PageVisits;
151+
152+
assert(data.page_visits === 2, 'page visits should be 2');
153+
});
154+
});

0 commit comments

Comments
 (0)