fix: Add preliminary handling for credit-only account designation

This commit is contained in:
Tyera Eulberg 2019-05-23 18:24:38 -06:00 committed by Michael Vines
parent 78ad376bcd
commit c99d8dd15c
9 changed files with 156 additions and 110 deletions

View File

@ -124,13 +124,13 @@ declare module '@solana/web3.js' {
declare export type TransactionSignature = string; declare export type TransactionSignature = string;
declare type TransactionInstructionCtorFields = {| declare type TransactionInstructionCtorFields = {|
keys: ?Array<{pubkey: PublicKey, isSigner: boolean}>, keys: ?Array<{pubkey: PublicKey, isSigner: boolean, isDebitable: boolean}>,
programId?: PublicKey, programId?: PublicKey,
data?: Buffer, data?: Buffer,
|}; |};
declare export class TransactionInstruction { declare export class TransactionInstruction {
keys: Array<{pubkey: PublicKey, isSigner: boolean}>; keys: Array<{pubkey: PublicKey, isSigner: boolean, isDebitable: boolean}>;
programId: PublicKey; programId: PublicKey;
data: Buffer; data: Buffer;
} }

View File

@ -201,7 +201,10 @@ export class BudgetProgram {
} }
return new Transaction().add({ return new Transaction().add({
keys: [{pubkey: from, isSigner: true}, {pubkey: to, isSigner: false}], keys: [
{pubkey: from, isSigner: true, isDebitable: true},
{pubkey: to, isSigner: false, isDebitable: false},
],
programId: this.programId, programId: this.programId,
data: data.slice(0, pos), data: data.slice(0, pos),
}); });
@ -222,9 +225,9 @@ export class BudgetProgram {
return new Transaction().add({ return new Transaction().add({
keys: [ keys: [
{pubkey: from, isSigner: true}, {pubkey: from, isSigner: true, isDebitable: true},
{pubkey: program, isSigner: false}, {pubkey: program, isSigner: false, isDebitable: true},
{pubkey: to, isSigner: false}, {pubkey: to, isSigner: false, isDebitable: false},
], ],
programId: this.programId, programId: this.programId,
data: data.slice(0, pos), data: data.slice(0, pos),
@ -246,9 +249,9 @@ export class BudgetProgram {
return new Transaction().add({ return new Transaction().add({
keys: [ keys: [
{pubkey: from, isSigner: true}, {pubkey: from, isSigner: true, isDebitable: true},
{pubkey: program, isSigner: false}, {pubkey: program, isSigner: false, isDebitable: true},
{pubkey: to, isSigner: false}, {pubkey: to, isSigner: false, isDebitable: false},
], ],
programId: this.programId, programId: this.programId,
data: data.slice(0, pos), data: data.slice(0, pos),
@ -294,9 +297,9 @@ export class BudgetProgram {
return new Transaction().add({ return new Transaction().add({
keys: [ keys: [
{pubkey: from, isSigner: true}, {pubkey: from, isSigner: true, isDebitable: true},
{pubkey: program, isSigner: false}, {pubkey: program, isSigner: false, isDebitable: true},
{pubkey: to, isSigner: false}, {pubkey: to, isSigner: false, isDebitable: false},
], ],
programId: this.programId, programId: this.programId,
data: data.slice(0, pos), data: data.slice(0, pos),
@ -321,9 +324,9 @@ export class BudgetProgram {
return new Transaction().add({ return new Transaction().add({
keys: [ keys: [
{pubkey: from, isSigner: true}, {pubkey: from, isSigner: true, isDebitable: true},
{pubkey: program, isSigner: false}, {pubkey: program, isSigner: false, isDebitable: true},
{pubkey: to, isSigner: false}, {pubkey: to, isSigner: false, isDebitable: false},
], ],
programId: this.programId, programId: this.programId,
data, data,
@ -351,9 +354,9 @@ export class BudgetProgram {
return new Transaction().add({ return new Transaction().add({
keys: [ keys: [
{pubkey: from, isSigner: true}, {pubkey: from, isSigner: true, isDebitable: true},
{pubkey: program, isSigner: false}, {pubkey: program, isSigner: false, isDebitable: true},
{pubkey: to, isSigner: false}, {pubkey: to, isSigner: false, isDebitable: false},
], ],
programId: this.programId, programId: this.programId,
data, data,

View File

@ -78,7 +78,7 @@ export class Loader {
); );
const transaction = new Transaction().add({ const transaction = new Transaction().add({
keys: [{pubkey: program.publicKey, isSigner: true}], keys: [{pubkey: program.publicKey, isSigner: true, isDebitable: true}],
programId, programId,
data, data,
}); });
@ -117,7 +117,7 @@ export class Loader {
); );
const transaction = new Transaction().add({ const transaction = new Transaction().add({
keys: [{pubkey: program.publicKey, isSigner: true}], keys: [{pubkey: program.publicKey, isSigner: true, isDebitable: true}],
programId, programId,
data, data,
}); });

View File

@ -49,8 +49,8 @@ export class SystemProgram {
return new Transaction().add({ return new Transaction().add({
keys: [ keys: [
{pubkey: from, isSigner: true}, {pubkey: from, isSigner: true, isDebitable: true},
{pubkey: newAccount, isSigner: false}, {pubkey: newAccount, isSigner: false, isDebitable: true},
], ],
programId: SystemProgram.programId, programId: SystemProgram.programId,
data, data,
@ -76,7 +76,10 @@ export class SystemProgram {
); );
return new Transaction().add({ return new Transaction().add({
keys: [{pubkey: from, isSigner: true}, {pubkey: to, isSigner: false}], keys: [
{pubkey: from, isSigner: true, isDebitable: true},
{pubkey: to, isSigner: false, isDebitable: false},
],
programId: SystemProgram.programId, programId: SystemProgram.programId,
data, data,
}); });
@ -101,7 +104,7 @@ export class SystemProgram {
); );
return new Transaction().add({ return new Transaction().add({
keys: [{pubkey: from, isSigner: true}], keys: [{pubkey: from, isSigner: true, isDebitable: true}],
programId: SystemProgram.programId, programId: SystemProgram.programId,
data, data,
}); });

View File

@ -237,8 +237,8 @@ export class Token {
transaction = new Transaction().add({ transaction = new Transaction().add({
keys: [ keys: [
{pubkey: tokenAccount.publicKey, isSigner: true}, {pubkey: tokenAccount.publicKey, isSigner: true, isDebitable: false},
{pubkey: initialAccountPublicKey, isSigner: false}, {pubkey: initialAccountPublicKey, isSigner: false, isDebitable: true},
], ],
programId, programId,
data, data,
@ -292,12 +292,12 @@ export class Token {
// Initialize the token account // Initialize the token account
const keys = [ const keys = [
{pubkey: tokenAccount.publicKey, isSigner: true}, {pubkey: tokenAccount.publicKey, isSigner: true, isDebitable: true},
{pubkey: owner.publicKey, isSigner: false}, {pubkey: owner.publicKey, isSigner: false, isDebitable: false},
{pubkey: this.token, isSigner: false}, {pubkey: this.token, isSigner: false, isDebitable: false},
]; ];
if (source) { if (source) {
keys.push({pubkey: source, isSigner: false}); keys.push({pubkey: source, isSigner: false, isDebitable: false});
} }
transaction = new Transaction().add({ transaction = new Transaction().add({
keys, keys,
@ -496,12 +496,16 @@ export class Token {
); );
const keys = [ const keys = [
{pubkey: owner, isSigner: true}, {pubkey: owner, isSigner: true, isDebitable: false},
{pubkey: source, isSigner: false}, {pubkey: source, isSigner: false, isDebitable: true},
{pubkey: destination, isSigner: false}, {pubkey: destination, isSigner: false, isDebitable: true},
]; ];
if (accountInfo.source) { if (accountInfo.source) {
keys.push({pubkey: accountInfo.source, isSigner: false}); keys.push({
pubkey: accountInfo.source,
isSigner: false,
isDebitable: true,
});
} }
return new TransactionInstruction({ return new TransactionInstruction({
keys, keys,
@ -540,9 +544,9 @@ export class Token {
return new TransactionInstruction({ return new TransactionInstruction({
keys: [ keys: [
{pubkey: owner, isSigner: true}, {pubkey: owner, isSigner: true, isDebitable: false},
{pubkey: account, isSigner: false}, {pubkey: account, isSigner: false, isDebitable: true},
{pubkey: delegate, isSigner: false}, {pubkey: delegate, isSigner: false, isDebitable: true},
], ],
programId: this.programId, programId: this.programId,
data, data,
@ -588,9 +592,9 @@ export class Token {
return new TransactionInstruction({ return new TransactionInstruction({
keys: [ keys: [
{pubkey: owner, isSigner: true}, {pubkey: owner, isSigner: true, isDebitable: false},
{pubkey: account, isSigner: false}, {pubkey: account, isSigner: false, isDebitable: true},
{pubkey: newOwner, isSigner: false}, {pubkey: newOwner, isSigner: false, isDebitable: true},
], ],
programId: this.programId, programId: this.programId,
data, data,

View File

@ -30,7 +30,7 @@ export const PACKET_DATA_SIZE = 512;
* @property {?Buffer} data * @property {?Buffer} data
*/ */
type TransactionInstructionCtorFields = {| type TransactionInstructionCtorFields = {|
keys?: Array<{pubkey: PublicKey, isSigner: boolean}>, keys?: Array<{pubkey: PublicKey, isSigner: boolean, isDebitable: boolean}>,
programId?: PublicKey, programId?: PublicKey,
data?: Buffer, data?: Buffer,
|}; |};
@ -43,7 +43,11 @@ export class TransactionInstruction {
* Public keys to include in this transaction * Public keys to include in this transaction
* Boolean represents whether this pubkey needs to sign the transaction * Boolean represents whether this pubkey needs to sign the transaction
*/ */
keys: Array<{pubkey: PublicKey, isSigner: boolean}> = []; keys: Array<{
pubkey: PublicKey,
isSigner: boolean,
isDebitable: boolean,
}> = [];
/** /**
* Program Id to execute * Program Id to execute
@ -166,6 +170,13 @@ export class Transaction {
if (!keys.includes(keyStr)) { if (!keys.includes(keyStr)) {
if (keySignerPair.isSigner) { if (keySignerPair.isSigner) {
numRequiredSignatures += 1; numRequiredSignatures += 1;
if (!keySignerPair.isDebitable) {
numCreditOnlySignedAccounts += 1;
}
} else {
if (!keySignerPair.isDebitable) {
numCreditOnlyUnsignedAccounts += 1;
}
} }
keys.push(keyStr); keys.push(keyStr);
} }
@ -422,6 +433,20 @@ export class Transaction {
const PUBKEY_LENGTH = 32; const PUBKEY_LENGTH = 32;
const SIGNATURE_LENGTH = 64; const SIGNATURE_LENGTH = 64;
function isCreditDebit(
i: number,
numRequiredSignatures: number,
numCreditOnlySignedAccounts: number,
numCreditOnlyUnsignedAccounts: number,
numKeys: number,
): boolean {
return (
i < numRequiredSignatures - numCreditOnlySignedAccounts ||
(i >= numRequiredSignatures &&
i < numKeys - numCreditOnlyUnsignedAccounts)
);
}
let transaction = new Transaction(); let transaction = new Transaction();
// Slice up wire data // Slice up wire data
@ -435,9 +460,12 @@ export class Transaction {
signatures.push(signature); signatures.push(signature);
} }
byteArray = byteArray.slice(1); // Skip numRequiredSignatures byte const numRequiredSignatures = byteArray.shift();
byteArray = byteArray.slice(1); // Skip numCreditOnlySignedAccounts byte // byteArray = byteArray.slice(1); // Skip numRequiredSignatures byte
byteArray = byteArray.slice(1); // Skip numCreditOnlyUnsignedAccounts byte const numCreditOnlySignedAccounts = byteArray.shift();
// byteArray = byteArray.slice(1); // Skip numCreditOnlySignedAccounts byte
const numCreditOnlyUnsignedAccounts = byteArray.shift();
// byteArray = byteArray.slice(1); // Skip numCreditOnlyUnsignedAccounts byte
const accountCount = shortvec.decodeLength(byteArray); const accountCount = shortvec.decodeLength(byteArray);
let accounts = []; let accounts = [];
@ -481,11 +509,19 @@ export class Transaction {
}; };
for (let j = 0; j < instructions[i].accountIndex.length; j++) { for (let j = 0; j < instructions[i].accountIndex.length; j++) {
const pubkey = new PublicKey(accounts[instructions[i].accountIndex[j]]); const pubkey = new PublicKey(accounts[instructions[i].accountIndex[j]]);
instructionData.keys.push({ instructionData.keys.push({
pubkey, pubkey,
isSigner: transaction.signatures.some( isSigner: transaction.signatures.some(
keyObj => keyObj.publicKey.toString() === pubkey.toString(), keyObj => keyObj.publicKey.toString() === pubkey.toString(),
), ),
isDebitable: isCreditDebit(
j,
numRequiredSignatures,
numCreditOnlySignedAccounts,
numCreditOnlyUnsignedAccounts,
accounts.length,
),
}); });
} }
let instruction = new TransactionInstruction(instructionData); let instruction = new TransactionInstruction(instructionData);

View File

@ -28,7 +28,7 @@ test('load BPF C program', async () => {
const data = await fs.readFile('test/fixtures/noop-c/noop.so'); const data = await fs.readFile('test/fixtures/noop-c/noop.so');
const programId = await BpfLoader.load(connection, from, data); const programId = await BpfLoader.load(connection, from, data);
const transaction = new Transaction().add({ const transaction = new Transaction().add({
keys: [{pubkey: from.publicKey, isSigner: true}], keys: [{pubkey: from.publicKey, isSigner: true, isDebitable: true}],
programId, programId,
}); });
await sendAndConfirmTransaction(connection, transaction, from); await sendAndConfirmTransaction(connection, transaction, from);
@ -47,7 +47,7 @@ test('load BPF Rust program', async () => {
); );
const programId = await BpfLoader.load(connection, from, data); const programId = await BpfLoader.load(connection, from, data);
const transaction = new Transaction().add({ const transaction = new Transaction().add({
keys: [{pubkey: from.publicKey, isSigner: true}], keys: [{pubkey: from.publicKey, isSigner: true, isDebitable: true}],
programId, programId,
}); });
await sendAndConfirmTransaction(connection, transaction, from); await sendAndConfirmTransaction(connection, transaction, from);

View File

@ -29,7 +29,7 @@ test('load native program', async () => {
'solana_noop_program', 'solana_noop_program',
); );
const transaction = new Transaction().add({ const transaction = new Transaction().add({
keys: [{pubkey: from.publicKey, isSigner: true}], keys: [{pubkey: from.publicKey, isSigner: true, isDebitable: true}],
programId, programId,
}); });

View File

@ -93,73 +93,73 @@ test('parse wire format and serialize', () => {
const wireTransaction = Buffer.from([ const wireTransaction = Buffer.from([
1, 1,
91, 47,
132, 50,
173, 66,
1,
218,
94,
253,
18,
27,
79,
207,
114,
27,
167,
127,
17, 17,
202, 219,
183, 90,
204, 187,
12, 49,
69,
243,
25,
206,
165,
116,
182,
64,
185,
168,
238,
168,
193,
140,
86,
83,
107,
252,
239,
80,
40, 40,
91, 77,
44, 8,
6, 58,
160, 129,
84, 51,
43, 76,
227,
63,
170,
255,
185,
132,
242,
82,
46,
124,
217,
127,
147,
24,
254,
157,
13, 13,
206,
126,
157,
189,
188,
53,
174,
42,
80,
4,
4,
212,
55,
67,
171,
34,
224,
81,
68,
230,
120,
117,
204,
241,
167,
152,
74,
141,
132,
73,
166,
217,
173,
27,
75,
62,
171,
160,
100,
159,
116,
164,
45,
185,
64,
0,
72,
4,
1, 1,
0, 0,
1, 2,
3, 3,
19, 19,
152, 152,