Skip to content

Commit 411ed32

Browse files
authored
[xc-admin] Header becomes class (#484)
* Header becomes class 2 * Revert test * Cleanup * Cleanup
1 parent 31ab162 commit 411ed32

File tree

3 files changed

+129
-159
lines changed

3 files changed

+129
-159
lines changed

xc-admin/packages/xc-admin-common/src/__tests__/GovernancePayload.test.ts

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,60 @@
1-
import { ChainName } from "@certusone/wormhole-sdk";
2-
import { PACKET_DATA_SIZE, PublicKey, SystemProgram } from "@solana/web3.js";
3-
import { ActionName, decodeHeader, encodeHeader, ExecutePostedVaa } from "..";
1+
import { PublicKey, SystemProgram } from "@solana/web3.js";
2+
import { PythGovernanceHeader, ExecutePostedVaa } from "..";
43

54
test("GovernancePayload ser/de", (done) => {
65
jest.setTimeout(60000);
76

87
// Valid header 1
9-
let expectedGovernanceHeader = {
10-
targetChainId: "pythnet" as ChainName,
11-
action: "ExecutePostedVaa" as ActionName,
12-
};
13-
let buffer = Buffer.alloc(PACKET_DATA_SIZE);
14-
let span = encodeHeader(expectedGovernanceHeader, buffer);
8+
let expectedGovernanceHeader = new PythGovernanceHeader(
9+
"pythnet",
10+
"ExecutePostedVaa"
11+
);
12+
let buffer = expectedGovernanceHeader.encode();
1513
expect(
16-
buffer.subarray(0, span).equals(Buffer.from([80, 84, 71, 77, 0, 0, 0, 26]))
14+
buffer.equals(Buffer.from([80, 84, 71, 77, 0, 0, 0, 26]))
1715
).toBeTruthy();
18-
19-
let governanceHeader = decodeHeader(buffer.subarray(0, span));
20-
expect(governanceHeader?.targetChainId).toBe("pythnet");
21-
expect(governanceHeader?.action).toBe("ExecutePostedVaa");
16+
let governanceHeader = PythGovernanceHeader.decode(buffer);
17+
expect(governanceHeader.targetChainId).toBe("pythnet");
18+
expect(governanceHeader.action).toBe("ExecutePostedVaa");
2219

2320
// Valid header 2
24-
expectedGovernanceHeader = {
25-
targetChainId: "unset" as ChainName,
26-
action: "ExecutePostedVaa" as ActionName,
27-
};
28-
buffer = Buffer.alloc(PACKET_DATA_SIZE);
29-
span = encodeHeader(expectedGovernanceHeader, buffer);
30-
expect(
31-
buffer.subarray(0, span).equals(Buffer.from([80, 84, 71, 77, 0, 0, 0, 0]))
32-
).toBeTruthy();
33-
governanceHeader = decodeHeader(buffer.subarray(0, span));
21+
expectedGovernanceHeader = new PythGovernanceHeader(
22+
"unset",
23+
"ExecutePostedVaa"
24+
);
25+
buffer = expectedGovernanceHeader.encode();
26+
expect(buffer.equals(Buffer.from([80, 84, 71, 77, 0, 0, 0, 0]))).toBeTruthy();
27+
governanceHeader = PythGovernanceHeader.decode(buffer);
3428
expect(governanceHeader?.targetChainId).toBe("unset");
3529
expect(governanceHeader?.action).toBe("ExecutePostedVaa");
3630

3731
// Valid header 3
38-
expectedGovernanceHeader = {
39-
targetChainId: "solana" as ChainName,
40-
action: "SetFee" as ActionName,
41-
};
42-
buffer = Buffer.alloc(PACKET_DATA_SIZE);
43-
span = encodeHeader(expectedGovernanceHeader, buffer);
44-
expect(
45-
buffer.subarray(0, span).equals(Buffer.from([80, 84, 71, 77, 1, 3, 0, 1]))
46-
).toBeTruthy();
47-
governanceHeader = decodeHeader(buffer.subarray(0, span));
32+
expectedGovernanceHeader = new PythGovernanceHeader("solana", "SetFee");
33+
buffer = expectedGovernanceHeader.encode();
34+
expect(buffer.equals(Buffer.from([80, 84, 71, 77, 1, 3, 0, 1]))).toBeTruthy();
35+
governanceHeader = PythGovernanceHeader.decode(buffer);
4836
expect(governanceHeader?.targetChainId).toBe("solana");
4937
expect(governanceHeader?.action).toBe("SetFee");
5038

5139
// Wrong magic number
5240
expect(() =>
53-
decodeHeader(Buffer.from([0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0]))
41+
PythGovernanceHeader.decode(
42+
Buffer.from([0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0])
43+
)
5444
).toThrow("Wrong magic number");
5545

5646
// Wrong chain
5747
expect(() =>
58-
decodeHeader(Buffer.from([80, 84, 71, 77, 0, 0, 255, 255, 0, 0, 0, 0]))
48+
PythGovernanceHeader.decode(
49+
Buffer.from([80, 84, 71, 77, 0, 0, 255, 255, 0, 0, 0, 0])
50+
)
5951
).toThrow("Chain Id not found");
6052

6153
// Wrong module/action combination
6254
expect(() =>
63-
decodeHeader(Buffer.from([80, 84, 71, 77, 0, 1, 0, 26, 0, 0, 0, 0]))
55+
PythGovernanceHeader.decode(
56+
Buffer.from([80, 84, 71, 77, 0, 1, 0, 26, 0, 0, 0, 0])
57+
)
6458
).toThrow("Invalid header, action doesn't match module");
6559

6660
// Decode executePostVaa with empty instructions
Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { ChainId, ChainName } from "@certusone/wormhole-sdk";
22
import * as BufferLayout from "@solana/buffer-layout";
3-
import {
4-
encodeHeader,
5-
governanceHeaderLayout,
6-
PythGovernanceAction,
7-
verifyHeader,
8-
} from ".";
3+
import { PythGovernanceAction, PythGovernanceHeader } from ".";
94
import { Layout } from "@solana/buffer-layout";
105
import {
116
AccountMeta,
@@ -56,30 +51,20 @@ export const accountMetaLayout = BufferLayout.struct<AccountMetadata>([
5651
BufferLayout.u8("isSigner"),
5752
BufferLayout.u8("isWritable"),
5853
]);
54+
5955
export const instructionDataLayout = BufferLayout.struct<InstructionData>([
6056
BufferLayout.blob(32, "programId"),
6157
new Vector<AccountMetadata>(accountMetaLayout, "accounts"),
6258
new Vector<number>(BufferLayout.u8(), "data"),
6359
]);
6460

65-
export const executePostedVaaLayout: BufferLayout.Structure<
66-
Readonly<{
67-
header: Readonly<{
68-
magicNumber: number;
69-
module: number;
70-
action: number;
71-
chain: ChainId;
72-
}>;
73-
instructions: InstructionData[];
74-
}>
75-
> = BufferLayout.struct([
76-
governanceHeaderLayout(),
77-
new Vector<InstructionData>(instructionDataLayout, "instructions"),
78-
]);
79-
8061
export class ExecutePostedVaa implements PythGovernanceAction {
8162
readonly targetChainId: ChainName;
8263
readonly instructions: TransactionInstruction[];
64+
static layout: Vector<InstructionData> = new Vector<InstructionData>(
65+
instructionDataLayout,
66+
"instructions"
67+
);
8368

8469
constructor(
8570
targetChainId: ChainName,
@@ -89,37 +74,36 @@ export class ExecutePostedVaa implements PythGovernanceAction {
8974
this.instructions = instructions;
9075
}
9176

92-
/** Decode ExecutePostedVaaArgs */
77+
/** Decode ExecutePostedVaa */
9378
static decode(data: Buffer): ExecutePostedVaa {
94-
let deserialized = executePostedVaaLayout.decode(data);
95-
96-
let header = verifyHeader(deserialized.header);
97-
98-
let instructions: TransactionInstruction[] = deserialized.instructions.map(
99-
(ix) => {
100-
let programId: PublicKey = new PublicKey(ix.programId);
101-
let keys: AccountMeta[] = ix.accounts.map((acc) => {
102-
return {
103-
pubkey: new PublicKey(acc.pubkey),
104-
isSigner: Boolean(acc.isSigner),
105-
isWritable: Boolean(acc.isWritable),
106-
};
107-
});
108-
let data: Buffer = Buffer.from(ix.data);
109-
return { programId, keys, data };
110-
}
79+
let header = PythGovernanceHeader.decode(data);
80+
let deserialized = this.layout.decode(
81+
data.subarray(PythGovernanceHeader.span)
11182
);
83+
let instructions: TransactionInstruction[] = deserialized.map((ix) => {
84+
let programId: PublicKey = new PublicKey(ix.programId);
85+
let keys: AccountMeta[] = ix.accounts.map((acc) => {
86+
return {
87+
pubkey: new PublicKey(acc.pubkey),
88+
isSigner: Boolean(acc.isSigner),
89+
isWritable: Boolean(acc.isWritable),
90+
};
91+
});
92+
let data: Buffer = Buffer.from(ix.data);
93+
return { programId, keys, data };
94+
});
11295
return new ExecutePostedVaa(header.targetChainId, instructions);
11396
}
11497

115-
/** Encode ExecutePostedVaaArgs */
98+
/** Encode ExecutePostedVaa */
11699
encode(): Buffer {
117-
// PACKET_DATA_SIZE is the maximum transaction size of Solana, so our serialized payload will never be bigger than that
100+
const headerBuffer = new PythGovernanceHeader(
101+
this.targetChainId,
102+
"ExecutePostedVaa"
103+
).encode();
104+
105+
// The code will crash if the payload is actually bigger than PACKET_DATA_SIZE. But PACKET_DATA_SIZE is the maximum transaction size of Solana, so our serialized payload should never be bigger than this anyway
118106
const buffer = Buffer.alloc(PACKET_DATA_SIZE);
119-
const offset = encodeHeader(
120-
{ action: "ExecutePostedVaa", targetChainId: this.targetChainId },
121-
buffer
122-
);
123107
let instructions: InstructionData[] = this.instructions.map((ix) => {
124108
let programId = ix.programId.toBytes();
125109
let accounts: AccountMetadata[] = ix.keys.map((acc) => {
@@ -133,13 +117,7 @@ export class ExecutePostedVaa implements PythGovernanceAction {
133117
return { programId, accounts, data };
134118
});
135119

136-
const span =
137-
offset +
138-
new Vector<InstructionData>(instructionDataLayout, "instructions").encode(
139-
instructions,
140-
buffer,
141-
offset
142-
);
143-
return buffer.subarray(0, span);
120+
const span = ExecutePostedVaa.layout.encode(instructions, buffer);
121+
return Buffer.concat([headerBuffer, buffer.subarray(0, span)]);
144122
}
145123
}

0 commit comments

Comments
 (0)