@solana/web3.js 1.56.0 → 1.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.browser.cjs.js +228 -4
- package/lib/index.browser.cjs.js.map +1 -1
- package/lib/index.browser.esm.js +228 -5
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +228 -4
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +2970 -2939
- package/lib/index.esm.js +228 -5
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +228 -4
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +3 -3
- package/lib/index.iife.min.js.map +1 -1
- package/lib/index.native.js +228 -4
- package/lib/index.native.js.map +1 -1
- package/package.json +1 -1
- package/src/connection.ts +6 -0
- package/src/message/account-keys.ts +79 -0
- package/src/message/compiled-keys.ts +165 -0
- package/src/message/index.ts +2 -0
- package/src/message/v0.ts +47 -0
- package/src/publickey.ts +12 -0
package/package.json
CHANGED
package/src/connection.ts
CHANGED
|
@@ -888,6 +888,8 @@ export type ParsedTransactionMeta = {
|
|
|
888
888
|
err: TransactionError | null;
|
|
889
889
|
/** The collection of addresses loaded using address lookup tables */
|
|
890
890
|
loadedAddresses?: LoadedAddresses;
|
|
891
|
+
/** The compute units consumed after processing the transaction */
|
|
892
|
+
computeUnitsConsumed?: number;
|
|
891
893
|
};
|
|
892
894
|
|
|
893
895
|
export type CompiledInnerInstruction = {
|
|
@@ -917,6 +919,8 @@ export type ConfirmedTransactionMeta = {
|
|
|
917
919
|
err: TransactionError | null;
|
|
918
920
|
/** The collection of addresses loaded using address lookup tables */
|
|
919
921
|
loadedAddresses?: LoadedAddresses;
|
|
922
|
+
/** The compute units consumed after processing the transaction */
|
|
923
|
+
computeUnitsConsumed?: number;
|
|
920
924
|
};
|
|
921
925
|
|
|
922
926
|
/**
|
|
@@ -1993,6 +1997,7 @@ const ConfirmedTransactionMetaResult = pick({
|
|
|
1993
1997
|
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
1994
1998
|
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
1995
1999
|
loadedAddresses: optional(LoadedAddressesResult),
|
|
2000
|
+
computeUnitsConsumed: optional(number()),
|
|
1996
2001
|
});
|
|
1997
2002
|
|
|
1998
2003
|
/**
|
|
@@ -2017,6 +2022,7 @@ const ParsedConfirmedTransactionMetaResult = pick({
|
|
|
2017
2022
|
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
2018
2023
|
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
2019
2024
|
loadedAddresses: optional(LoadedAddressesResult),
|
|
2025
|
+
computeUnitsConsumed: optional(number()),
|
|
2020
2026
|
});
|
|
2021
2027
|
|
|
2022
2028
|
const TransactionVersionStruct = union([literal(0), literal('legacy')]);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {LoadedAddresses} from '../connection';
|
|
2
|
+
import {PublicKey} from '../publickey';
|
|
3
|
+
import {TransactionInstruction} from '../transaction';
|
|
4
|
+
import {MessageCompiledInstruction} from './index';
|
|
5
|
+
|
|
6
|
+
export type AccountKeysFromLookups = LoadedAddresses;
|
|
7
|
+
|
|
8
|
+
export class MessageAccountKeys {
|
|
9
|
+
staticAccountKeys: Array<PublicKey>;
|
|
10
|
+
accountKeysFromLookups?: AccountKeysFromLookups;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
staticAccountKeys: Array<PublicKey>,
|
|
14
|
+
accountKeysFromLookups?: AccountKeysFromLookups,
|
|
15
|
+
) {
|
|
16
|
+
this.staticAccountKeys = staticAccountKeys;
|
|
17
|
+
this.accountKeysFromLookups = accountKeysFromLookups;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
keySegments(): Array<Array<PublicKey>> {
|
|
21
|
+
const keySegments = [this.staticAccountKeys];
|
|
22
|
+
if (this.accountKeysFromLookups) {
|
|
23
|
+
keySegments.push(this.accountKeysFromLookups.writable);
|
|
24
|
+
keySegments.push(this.accountKeysFromLookups.readonly);
|
|
25
|
+
}
|
|
26
|
+
return keySegments;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get(index: number): PublicKey | undefined {
|
|
30
|
+
for (const keySegment of this.keySegments()) {
|
|
31
|
+
if (index < keySegment.length) {
|
|
32
|
+
return keySegment[index];
|
|
33
|
+
} else {
|
|
34
|
+
index -= keySegment.length;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get length(): number {
|
|
41
|
+
return this.keySegments().flat().length;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
compileInstructions(
|
|
45
|
+
instructions: Array<TransactionInstruction>,
|
|
46
|
+
): Array<MessageCompiledInstruction> {
|
|
47
|
+
// Bail early if any account indexes would overflow a u8
|
|
48
|
+
const U8_MAX = 255;
|
|
49
|
+
if (this.length > U8_MAX + 1) {
|
|
50
|
+
throw new Error('Account index overflow encountered during compilation');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const keyIndexMap = new Map();
|
|
54
|
+
this.keySegments()
|
|
55
|
+
.flat()
|
|
56
|
+
.forEach((key, index) => {
|
|
57
|
+
keyIndexMap.set(key.toBase58(), index);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const findKeyIndex = (key: PublicKey) => {
|
|
61
|
+
const keyIndex = keyIndexMap.get(key.toBase58());
|
|
62
|
+
if (keyIndex === undefined)
|
|
63
|
+
throw new Error(
|
|
64
|
+
'Encountered an unknown instruction account key during compilation',
|
|
65
|
+
);
|
|
66
|
+
return keyIndex;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return instructions.map((instruction): MessageCompiledInstruction => {
|
|
70
|
+
return {
|
|
71
|
+
programIdIndex: findKeyIndex(instruction.programId),
|
|
72
|
+
accountKeyIndexes: instruction.keys.map(meta =>
|
|
73
|
+
findKeyIndex(meta.pubkey),
|
|
74
|
+
),
|
|
75
|
+
data: instruction.data,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import {MessageHeader, MessageAddressTableLookup} from './index';
|
|
2
|
+
import {AccountKeysFromLookups} from './account-keys';
|
|
3
|
+
import {AddressLookupTableAccount} from '../programs';
|
|
4
|
+
import {TransactionInstruction} from '../transaction';
|
|
5
|
+
import assert from '../utils/assert';
|
|
6
|
+
import {PublicKey} from '../publickey';
|
|
7
|
+
|
|
8
|
+
export type CompiledKeyMeta = {
|
|
9
|
+
isSigner: boolean;
|
|
10
|
+
isWritable: boolean;
|
|
11
|
+
isInvoked: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type KeyMetaMap = Map<string, CompiledKeyMeta>;
|
|
15
|
+
|
|
16
|
+
export class CompiledKeys {
|
|
17
|
+
payer: PublicKey;
|
|
18
|
+
keyMetaMap: KeyMetaMap;
|
|
19
|
+
|
|
20
|
+
constructor(payer: PublicKey, keyMetaMap: KeyMetaMap) {
|
|
21
|
+
this.payer = payer;
|
|
22
|
+
this.keyMetaMap = keyMetaMap;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static compile(
|
|
26
|
+
instructions: Array<TransactionInstruction>,
|
|
27
|
+
payer: PublicKey,
|
|
28
|
+
): CompiledKeys {
|
|
29
|
+
const keyMetaMap: KeyMetaMap = new Map();
|
|
30
|
+
const getOrInsertDefault = (pubkey: PublicKey): CompiledKeyMeta => {
|
|
31
|
+
const address = pubkey.toBase58();
|
|
32
|
+
let keyMeta = keyMetaMap.get(address);
|
|
33
|
+
if (keyMeta === undefined) {
|
|
34
|
+
keyMeta = {
|
|
35
|
+
isSigner: false,
|
|
36
|
+
isWritable: false,
|
|
37
|
+
isInvoked: false,
|
|
38
|
+
};
|
|
39
|
+
keyMetaMap.set(address, keyMeta);
|
|
40
|
+
}
|
|
41
|
+
return keyMeta;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const payerKeyMeta = getOrInsertDefault(payer);
|
|
45
|
+
payerKeyMeta.isSigner = true;
|
|
46
|
+
payerKeyMeta.isWritable = true;
|
|
47
|
+
|
|
48
|
+
for (const ix of instructions) {
|
|
49
|
+
getOrInsertDefault(ix.programId).isInvoked = true;
|
|
50
|
+
for (const accountMeta of ix.keys) {
|
|
51
|
+
const keyMeta = getOrInsertDefault(accountMeta.pubkey);
|
|
52
|
+
keyMeta.isSigner ||= accountMeta.isSigner;
|
|
53
|
+
keyMeta.isWritable ||= accountMeta.isWritable;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return new CompiledKeys(payer, keyMetaMap);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getMessageComponents(): [MessageHeader, Array<PublicKey>] {
|
|
61
|
+
const mapEntries = [...this.keyMetaMap.entries()];
|
|
62
|
+
assert(mapEntries.length <= 256, 'Max static account keys length exceeded');
|
|
63
|
+
|
|
64
|
+
const writableSigners = mapEntries.filter(
|
|
65
|
+
([, meta]) => meta.isSigner && meta.isWritable,
|
|
66
|
+
);
|
|
67
|
+
const readonlySigners = mapEntries.filter(
|
|
68
|
+
([, meta]) => meta.isSigner && !meta.isWritable,
|
|
69
|
+
);
|
|
70
|
+
const writableNonSigners = mapEntries.filter(
|
|
71
|
+
([, meta]) => !meta.isSigner && meta.isWritable,
|
|
72
|
+
);
|
|
73
|
+
const readonlyNonSigners = mapEntries.filter(
|
|
74
|
+
([, meta]) => !meta.isSigner && !meta.isWritable,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const header: MessageHeader = {
|
|
78
|
+
numRequiredSignatures: writableSigners.length + readonlySigners.length,
|
|
79
|
+
numReadonlySignedAccounts: readonlySigners.length,
|
|
80
|
+
numReadonlyUnsignedAccounts: readonlyNonSigners.length,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// sanity checks
|
|
84
|
+
{
|
|
85
|
+
assert(
|
|
86
|
+
writableSigners.length > 0,
|
|
87
|
+
'Expected at least one writable signer key',
|
|
88
|
+
);
|
|
89
|
+
const [payerAddress] = writableSigners[0];
|
|
90
|
+
assert(
|
|
91
|
+
payerAddress === this.payer.toBase58(),
|
|
92
|
+
'Expected first writable signer key to be the fee payer',
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const staticAccountKeys = [
|
|
97
|
+
...writableSigners.map(([address]) => new PublicKey(address)),
|
|
98
|
+
...readonlySigners.map(([address]) => new PublicKey(address)),
|
|
99
|
+
...writableNonSigners.map(([address]) => new PublicKey(address)),
|
|
100
|
+
...readonlyNonSigners.map(([address]) => new PublicKey(address)),
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
return [header, staticAccountKeys];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
extractTableLookup(
|
|
107
|
+
lookupTable: AddressLookupTableAccount,
|
|
108
|
+
): [MessageAddressTableLookup, AccountKeysFromLookups] | undefined {
|
|
109
|
+
const [writableIndexes, drainedWritableKeys] =
|
|
110
|
+
this.drainKeysFoundInLookupTable(
|
|
111
|
+
lookupTable.state.addresses,
|
|
112
|
+
keyMeta =>
|
|
113
|
+
!keyMeta.isSigner && !keyMeta.isInvoked && keyMeta.isWritable,
|
|
114
|
+
);
|
|
115
|
+
const [readonlyIndexes, drainedReadonlyKeys] =
|
|
116
|
+
this.drainKeysFoundInLookupTable(
|
|
117
|
+
lookupTable.state.addresses,
|
|
118
|
+
keyMeta =>
|
|
119
|
+
!keyMeta.isSigner && !keyMeta.isInvoked && !keyMeta.isWritable,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Don't extract lookup if no keys were found
|
|
123
|
+
if (writableIndexes.length === 0 && readonlyIndexes.length === 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [
|
|
128
|
+
{
|
|
129
|
+
accountKey: lookupTable.key,
|
|
130
|
+
writableIndexes,
|
|
131
|
+
readonlyIndexes,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
writable: drainedWritableKeys,
|
|
135
|
+
readonly: drainedReadonlyKeys,
|
|
136
|
+
},
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** @internal */
|
|
141
|
+
private drainKeysFoundInLookupTable(
|
|
142
|
+
lookupTableEntries: Array<PublicKey>,
|
|
143
|
+
keyMetaFilter: (keyMeta: CompiledKeyMeta) => boolean,
|
|
144
|
+
): [Array<number>, Array<PublicKey>] {
|
|
145
|
+
const lookupTableIndexes = new Array();
|
|
146
|
+
const drainedKeys = new Array();
|
|
147
|
+
|
|
148
|
+
for (const [address, keyMeta] of this.keyMetaMap.entries()) {
|
|
149
|
+
if (keyMetaFilter(keyMeta)) {
|
|
150
|
+
const key = new PublicKey(address);
|
|
151
|
+
const lookupTableIndex = lookupTableEntries.findIndex(entry =>
|
|
152
|
+
entry.equals(key),
|
|
153
|
+
);
|
|
154
|
+
if (lookupTableIndex >= 0) {
|
|
155
|
+
assert(lookupTableIndex < 256, 'Max lookup table index exceeded');
|
|
156
|
+
lookupTableIndexes.push(lookupTableIndex);
|
|
157
|
+
drainedKeys.push(key);
|
|
158
|
+
this.keyMetaMap.delete(address);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return [lookupTableIndexes, drainedKeys];
|
|
164
|
+
}
|
|
165
|
+
}
|
package/src/message/index.ts
CHANGED
package/src/message/v0.ts
CHANGED
|
@@ -12,6 +12,10 @@ import {PublicKey, PUBLIC_KEY_LENGTH} from '../publickey';
|
|
|
12
12
|
import * as shortvec from '../utils/shortvec-encoding';
|
|
13
13
|
import assert from '../utils/assert';
|
|
14
14
|
import {PACKET_DATA_SIZE, VERSION_PREFIX_MASK} from '../transaction/constants';
|
|
15
|
+
import {TransactionInstruction} from '../transaction';
|
|
16
|
+
import {AddressLookupTableAccount} from '../programs';
|
|
17
|
+
import {CompiledKeys} from './compiled-keys';
|
|
18
|
+
import {AccountKeysFromLookups, MessageAccountKeys} from './account-keys';
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* Message constructor arguments
|
|
@@ -29,6 +33,13 @@ export type MessageV0Args = {
|
|
|
29
33
|
addressTableLookups: MessageAddressTableLookup[];
|
|
30
34
|
};
|
|
31
35
|
|
|
36
|
+
export type CompileV0Args = {
|
|
37
|
+
payerKey: PublicKey;
|
|
38
|
+
instructions: Array<TransactionInstruction>;
|
|
39
|
+
recentBlockhash: Blockhash;
|
|
40
|
+
addressLookupTableAccounts?: Array<AddressLookupTableAccount>;
|
|
41
|
+
};
|
|
42
|
+
|
|
32
43
|
export class MessageV0 {
|
|
33
44
|
header: MessageHeader;
|
|
34
45
|
staticAccountKeys: Array<PublicKey>;
|
|
@@ -48,6 +59,42 @@ export class MessageV0 {
|
|
|
48
59
|
return 0;
|
|
49
60
|
}
|
|
50
61
|
|
|
62
|
+
static compile(args: CompileV0Args): MessageV0 {
|
|
63
|
+
const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey);
|
|
64
|
+
|
|
65
|
+
const addressTableLookups = new Array<MessageAddressTableLookup>();
|
|
66
|
+
const accountKeysFromLookups: AccountKeysFromLookups = {
|
|
67
|
+
writable: new Array(),
|
|
68
|
+
readonly: new Array(),
|
|
69
|
+
};
|
|
70
|
+
const lookupTableAccounts = args.addressLookupTableAccounts || [];
|
|
71
|
+
for (const lookupTable of lookupTableAccounts) {
|
|
72
|
+
const extractResult = compiledKeys.extractTableLookup(lookupTable);
|
|
73
|
+
if (extractResult !== undefined) {
|
|
74
|
+
const [addressTableLookup, {writable, readonly}] = extractResult;
|
|
75
|
+
addressTableLookups.push(addressTableLookup);
|
|
76
|
+
accountKeysFromLookups.writable.push(...writable);
|
|
77
|
+
accountKeysFromLookups.readonly.push(...readonly);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const [header, staticAccountKeys] = compiledKeys.getMessageComponents();
|
|
82
|
+
const accountKeys = new MessageAccountKeys(
|
|
83
|
+
staticAccountKeys,
|
|
84
|
+
accountKeysFromLookups,
|
|
85
|
+
);
|
|
86
|
+
const compiledInstructions = accountKeys.compileInstructions(
|
|
87
|
+
args.instructions,
|
|
88
|
+
);
|
|
89
|
+
return new MessageV0({
|
|
90
|
+
header,
|
|
91
|
+
staticAccountKeys,
|
|
92
|
+
recentBlockhash: args.recentBlockhash,
|
|
93
|
+
compiledInstructions,
|
|
94
|
+
addressTableLookups,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
51
98
|
serialize(): Uint8Array {
|
|
52
99
|
const encodedStaticAccountKeysLength = Array<number>();
|
|
53
100
|
shortvec.encodeLength(
|
package/src/publickey.ts
CHANGED
|
@@ -40,6 +40,9 @@ function isPublicKeyData(value: PublicKeyInitData): value is PublicKeyData {
|
|
|
40
40
|
return (value as PublicKeyData)._bn !== undefined;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// local counter used by PublicKey.unique()
|
|
44
|
+
let uniquePublicKeyCounter = 1;
|
|
45
|
+
|
|
43
46
|
/**
|
|
44
47
|
* A public key
|
|
45
48
|
*/
|
|
@@ -73,6 +76,15 @@ export class PublicKey extends Struct {
|
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Returns a unique PublicKey for tests and benchmarks using acounter
|
|
81
|
+
*/
|
|
82
|
+
static unique(): PublicKey {
|
|
83
|
+
const key = new PublicKey(uniquePublicKeyCounter);
|
|
84
|
+
uniquePublicKeyCounter += 1;
|
|
85
|
+
return new PublicKey(key.toBuffer());
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
/**
|
|
77
89
|
* Default public key value. (All zeros)
|
|
78
90
|
*/
|