fix: support multiple Transaction signatures
This commit is contained in:
parent
5311ed7f68
commit
fa7e2722d1
|
@ -76,7 +76,7 @@ showBalance()
|
||||||
0,
|
0,
|
||||||
solanaWeb3.BudgetProgram.programId,
|
solanaWeb3.BudgetProgram.programId,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -89,7 +89,7 @@ showBalance()
|
||||||
solanaWeb3.BudgetProgram.space,
|
solanaWeb3.BudgetProgram.space,
|
||||||
solanaWeb3.BudgetProgram.programId,
|
solanaWeb3.BudgetProgram.programId,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -105,7 +105,7 @@ showBalance()
|
||||||
new Date('2050'),
|
new Date('2050'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(contractFunds, transaction);
|
return connection.sendTransaction(transaction, contractFunds);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -117,7 +117,7 @@ showBalance()
|
||||||
account2.publicKey,
|
account2.publicKey,
|
||||||
new Date('2050'),
|
new Date('2050'),
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
|
|
@ -74,7 +74,7 @@ showBalance()
|
||||||
approver1.publicKey,
|
approver1.publicKey,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -84,7 +84,7 @@ showBalance()
|
||||||
approver2.publicKey,
|
approver2.publicKey,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -97,7 +97,7 @@ showBalance()
|
||||||
0,
|
0,
|
||||||
solanaWeb3.BudgetProgram.programId,
|
solanaWeb3.BudgetProgram.programId,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -110,7 +110,7 @@ showBalance()
|
||||||
solanaWeb3.BudgetProgram.space,
|
solanaWeb3.BudgetProgram.space,
|
||||||
solanaWeb3.BudgetProgram.programId,
|
solanaWeb3.BudgetProgram.programId,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(account1, transaction);
|
return connection.sendTransaction(transaction, account1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -124,7 +124,7 @@ showBalance()
|
||||||
solanaWeb3.BudgetProgram.signatureCondition(approver1.publicKey),
|
solanaWeb3.BudgetProgram.signatureCondition(approver1.publicKey),
|
||||||
solanaWeb3.BudgetProgram.signatureCondition(approver2.publicKey),
|
solanaWeb3.BudgetProgram.signatureCondition(approver2.publicKey),
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(contractFunds, transaction);
|
return connection.sendTransaction(transaction, contractFunds);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -135,7 +135,7 @@ showBalance()
|
||||||
contractState.publicKey,
|
contractState.publicKey,
|
||||||
account2.publicKey,
|
account2.publicKey,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(approver1, transaction);
|
return connection.sendTransaction(transaction, approver1);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
@ -146,7 +146,7 @@ showBalance()
|
||||||
contractState.publicKey,
|
contractState.publicKey,
|
||||||
account2.publicKey,
|
account2.publicKey,
|
||||||
);
|
);
|
||||||
return connection.sendTransaction(approver2, transaction);
|
return connection.sendTransaction(transaction, approver2);
|
||||||
})
|
})
|
||||||
.then(confirmTransaction)
|
.then(confirmTransaction)
|
||||||
.then(showBalance)
|
.then(showBalance)
|
||||||
|
|
|
@ -66,8 +66,8 @@ declare module '@solana/web3.js' {
|
||||||
amount: number,
|
amount: number,
|
||||||
): Promise<TransactionSignature>;
|
): Promise<TransactionSignature>;
|
||||||
sendTransaction(
|
sendTransaction(
|
||||||
from: Account,
|
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
|
...signers: Array<Account>
|
||||||
): Promise<TransactionSignature>;
|
): Promise<TransactionSignature>;
|
||||||
onAccountChange(
|
onAccountChange(
|
||||||
publickey: PublicKey,
|
publickey: PublicKey,
|
||||||
|
@ -242,8 +242,7 @@ declare module '@solana/web3.js' {
|
||||||
// === src/util/send-and-confirm-transaction.js ===
|
// === src/util/send-and-confirm-transaction.js ===
|
||||||
declare export function sendAndConfirmTransaction(
|
declare export function sendAndConfirmTransaction(
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
from: Account,
|
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
runtimeErrorOk?: boolean,
|
...signers: Array<Account>
|
||||||
): Promise<TransactionSignature>;
|
): Promise<TransactionSignature>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class BpfLoader {
|
||||||
elf.length,
|
elf.length,
|
||||||
BpfLoader.programId,
|
BpfLoader.programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, owner, transaction);
|
await sendAndConfirmTransaction(connection, transaction, owner);
|
||||||
|
|
||||||
const loader = new Loader(connection, BpfLoader.programId);
|
const loader = new Loader(connection, BpfLoader.programId);
|
||||||
await loader.load(programAccount, elf);
|
await loader.load(programAccount, elf);
|
||||||
|
|
|
@ -368,8 +368,8 @@ export class Connection {
|
||||||
* Sign and send a transaction
|
* Sign and send a transaction
|
||||||
*/
|
*/
|
||||||
async sendTransaction(
|
async sendTransaction(
|
||||||
from: Account,
|
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
|
...signers: Array<Account>
|
||||||
): Promise<TransactionSignature> {
|
): Promise<TransactionSignature> {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Attempt to use the previous last id for up to 1 second
|
// Attempt to use the previous last id for up to 1 second
|
||||||
|
@ -379,7 +379,7 @@ export class Connection {
|
||||||
this._lastIdInfo.seconds === seconds
|
this._lastIdInfo.seconds === seconds
|
||||||
) {
|
) {
|
||||||
transaction.lastId = this._lastIdInfo.lastId;
|
transaction.lastId = this._lastIdInfo.lastId;
|
||||||
transaction.sign(from);
|
transaction.sign(...signers);
|
||||||
if (!transaction.signature) {
|
if (!transaction.signature) {
|
||||||
throw new Error('!signature'); // should never happen
|
throw new Error('!signature'); // should never happen
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ export class Loader {
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
transactions.push(
|
transactions.push(
|
||||||
sendAndConfirmTransaction(this.connection, program, transaction),
|
sendAndConfirmTransaction(this.connection, transaction, program),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Run up to 8 Loads in parallel to prevent too many parallel transactions from
|
// Run up to 8 Loads in parallel to prevent too many parallel transactions from
|
||||||
|
@ -116,6 +116,6 @@ export class Loader {
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
transaction.add(SystemProgram.spawn(program.publicKey));
|
transaction.add(SystemProgram.spawn(program.publicKey));
|
||||||
await sendAndConfirmTransaction(this.connection, program, transaction);
|
await sendAndConfirmTransaction(this.connection, transaction, program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class NativeLoader {
|
||||||
bytes.length + 1,
|
bytes.length + 1,
|
||||||
NativeLoader.programId,
|
NativeLoader.programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, owner, transaction);
|
await sendAndConfirmTransaction(connection, transaction, owner);
|
||||||
|
|
||||||
const loader = new Loader(connection, NativeLoader.programId);
|
const loader = new Loader(connection, NativeLoader.programId);
|
||||||
await loader.load(programAccount, bytes);
|
await loader.load(programAccount, bytes);
|
||||||
|
|
|
@ -233,14 +233,14 @@ export class Token {
|
||||||
1 + userdata.length,
|
1 + userdata.length,
|
||||||
programId,
|
programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, owner, transaction);
|
await sendAndConfirmTransaction(connection, transaction, owner);
|
||||||
|
|
||||||
transaction = new Transaction().add({
|
transaction = new Transaction().add({
|
||||||
keys: [tokenAccount.publicKey, initialAccountPublicKey],
|
keys: [tokenAccount.publicKey, initialAccountPublicKey],
|
||||||
programId,
|
programId,
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, tokenAccount, transaction);
|
await sendAndConfirmTransaction(connection, transaction, tokenAccount);
|
||||||
|
|
||||||
return [token, initialAccountPublicKey];
|
return [token, initialAccountPublicKey];
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ export class Token {
|
||||||
1 + TokenAccountInfoLayout.span,
|
1 + TokenAccountInfoLayout.span,
|
||||||
this.programId,
|
this.programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
await sendAndConfirmTransaction(this.connection, transaction, owner);
|
||||||
|
|
||||||
// Initialize the token account
|
// Initialize the token account
|
||||||
const keys = [tokenAccount.publicKey, owner.publicKey, this.token];
|
const keys = [tokenAccount.publicKey, owner.publicKey, this.token];
|
||||||
|
@ -295,7 +295,7 @@ export class Token {
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
|
|
||||||
await sendAndConfirmTransaction(this.connection, tokenAccount, transaction);
|
await sendAndConfirmTransaction(this.connection, transaction, tokenAccount);
|
||||||
|
|
||||||
return tokenAccount.publicKey;
|
return tokenAccount.publicKey;
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,6 @@ export class Token {
|
||||||
): Promise<?TransactionSignature> {
|
): Promise<?TransactionSignature> {
|
||||||
return await sendAndConfirmTransaction(
|
return await sendAndConfirmTransaction(
|
||||||
this.connection,
|
this.connection,
|
||||||
owner,
|
|
||||||
new Transaction().add(
|
new Transaction().add(
|
||||||
await this.transferInstruction(
|
await this.transferInstruction(
|
||||||
owner.publicKey,
|
owner.publicKey,
|
||||||
|
@ -386,6 +385,7 @@ export class Token {
|
||||||
amount,
|
amount,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
owner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,10 +405,10 @@ export class Token {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await sendAndConfirmTransaction(
|
await sendAndConfirmTransaction(
|
||||||
this.connection,
|
this.connection,
|
||||||
owner,
|
|
||||||
new Transaction().add(
|
new Transaction().add(
|
||||||
this.approveInstruction(owner.publicKey, account, delegate, amount),
|
this.approveInstruction(owner.publicKey, account, delegate, amount),
|
||||||
),
|
),
|
||||||
|
owner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,10 +441,10 @@ export class Token {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await sendAndConfirmTransaction(
|
await sendAndConfirmTransaction(
|
||||||
this.connection,
|
this.connection,
|
||||||
owner,
|
|
||||||
new Transaction().add(
|
new Transaction().add(
|
||||||
this.setOwnerInstruction(owner.publicKey, account, newOwner),
|
this.setOwnerInstruction(owner.publicKey, account, newOwner),
|
||||||
),
|
),
|
||||||
|
owner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import assert from 'assert';
|
import invariant from 'assert';
|
||||||
import * as BufferLayout from 'buffer-layout';
|
import * as BufferLayout from 'buffer-layout';
|
||||||
import nacl from 'tweetnacl';
|
import nacl from 'tweetnacl';
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
|
@ -61,25 +61,39 @@ export class TransactionInstruction {
|
||||||
* List of Transaction object fields that may be initialized at construction
|
* List of Transaction object fields that may be initialized at construction
|
||||||
*
|
*
|
||||||
* @typedef {Object} TransactionCtorFields
|
* @typedef {Object} TransactionCtorFields
|
||||||
* @property {?Buffer} signature
|
|
||||||
* @property {?Array<PublicKey>} keys
|
|
||||||
* @property {?PublicKey} programId
|
|
||||||
* @property {?number} fee
|
* @property {?number} fee
|
||||||
* @property {?Buffer} userdata
|
|
||||||
*/
|
*/
|
||||||
type TransactionCtorFields = {|
|
type TransactionCtorFields = {|
|
||||||
fee?: number,
|
fee?: number,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
type SignaturePubkeyPair = {|
|
||||||
|
signature: Buffer | null,
|
||||||
|
publicKey: PublicKey,
|
||||||
|
|};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction class
|
* Transaction class
|
||||||
*/
|
*/
|
||||||
export class Transaction {
|
export class Transaction {
|
||||||
/**
|
/**
|
||||||
* Current signature of the transaction. Typically created by invoking the
|
* Signatures for the transaction. Typically created by invoking the
|
||||||
* `sign()` method
|
* `sign()` method one or more times.
|
||||||
*/
|
*/
|
||||||
signature: ?Buffer;
|
signatures: Array<SignaturePubkeyPair> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first (primary) Transaction signature
|
||||||
|
*/
|
||||||
|
get signature(): Buffer | null {
|
||||||
|
if (this.signatures.length > 0) {
|
||||||
|
return this.signatures[0].signature;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The instructions to atomically execute
|
* The instructions to atomically execute
|
||||||
|
@ -128,7 +142,7 @@ export class Transaction {
|
||||||
throw new Error('No instructions provided');
|
throw new Error('No instructions provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = [];
|
const keys = this.signatures.map(({publicKey}) => publicKey.toString());
|
||||||
const programIds = [];
|
const programIds = [];
|
||||||
this.instructions.forEach(instruction => {
|
this.instructions.forEach(instruction => {
|
||||||
const programId = instruction.programId.toString();
|
const programId = instruction.programId.toString();
|
||||||
|
@ -153,8 +167,8 @@ export class Transaction {
|
||||||
});
|
});
|
||||||
|
|
||||||
instructions.forEach(instruction => {
|
instructions.forEach(instruction => {
|
||||||
assert(instruction.programIdIndex >= 0);
|
invariant(instruction.programIdIndex >= 0);
|
||||||
instruction.keyIndices.forEach(keyIndex => assert(keyIndex >= 0));
|
instruction.keyIndices.forEach(keyIndex => invariant(keyIndex >= 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
const instructionLayout = BufferLayout.struct([
|
const instructionLayout = BufferLayout.struct([
|
||||||
|
@ -222,14 +236,34 @@ export class Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign the Transaction with the specified account
|
* Sign the Transaction with the specified accounts. Multiple signatures may
|
||||||
|
* be applied to a Transaction. The first signature is considered "primary"
|
||||||
|
* and is used when testing for Transaction confirmation.
|
||||||
|
*
|
||||||
|
* Transaction fields should not be modified after the first call to `sign`,
|
||||||
|
* as doing so may invalidate the signature and cause the Transaction to be
|
||||||
|
* rejected.
|
||||||
*
|
*
|
||||||
* The Transaction must be assigned a valid `lastId` before invoking this method
|
* The Transaction must be assigned a valid `lastId` before invoking this method
|
||||||
*/
|
*/
|
||||||
sign(from: Account) {
|
sign(...signers: Array<Account>) {
|
||||||
|
if (signers.length === 0) {
|
||||||
|
throw new Error('No signers');
|
||||||
|
}
|
||||||
|
const signatures: Array<SignaturePubkeyPair> = signers.map(account => {
|
||||||
|
return {
|
||||||
|
signature: null,
|
||||||
|
publicKey: account.publicKey,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.signatures = signatures;
|
||||||
const signData = this._getSignData();
|
const signData = this._getSignData();
|
||||||
this.signature = nacl.sign.detached(signData, from.secretKey);
|
|
||||||
assert(this.signature.length === 64);
|
signers.forEach((account, index) => {
|
||||||
|
const signature = nacl.sign.detached(signData, account.secretKey);
|
||||||
|
invariant(signature.length === 64);
|
||||||
|
signatures[index].signature = signature;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,19 +272,27 @@ export class Transaction {
|
||||||
* The Transaction must have a valid `signature` before invoking this method
|
* The Transaction must have a valid `signature` before invoking this method
|
||||||
*/
|
*/
|
||||||
serialize(): Buffer {
|
serialize(): Buffer {
|
||||||
const {signature} = this;
|
const {signatures} = this;
|
||||||
if (!signature) {
|
if (!signatures) {
|
||||||
throw new Error('Transaction has not been signed');
|
throw new Error('Transaction has not been signed');
|
||||||
}
|
}
|
||||||
|
|
||||||
const signData = this._getSignData();
|
const signData = this._getSignData();
|
||||||
const wireTransaction = Buffer.alloc(
|
const wireTransaction = Buffer.alloc(
|
||||||
8 + signature.length + signData.length,
|
8 + signatures.length * 64 + signData.length,
|
||||||
|
);
|
||||||
|
invariant(signatures.length < 256);
|
||||||
|
wireTransaction.writeUInt8(signatures.length, 0);
|
||||||
|
signatures.forEach(({signature}, index) => {
|
||||||
|
invariant(signature !== null, `null signature`);
|
||||||
|
invariant(signature.length === 64, `signature has invalid length`);
|
||||||
|
Buffer.from(signature).copy(wireTransaction, 8 + index * 64);
|
||||||
|
});
|
||||||
|
signData.copy(wireTransaction, 8 + signatures.length * 64);
|
||||||
|
invariant(
|
||||||
|
wireTransaction.length < 512,
|
||||||
|
`${wireTransaction.length}, ${signatures.length}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
wireTransaction.writeUInt8(1, 0); // TODO: Support multiple transaction signatures
|
|
||||||
Buffer.from(signature).copy(wireTransaction, 8);
|
|
||||||
signData.copy(wireTransaction, 8 + signature.length);
|
|
||||||
return wireTransaction;
|
return wireTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +301,7 @@ export class Transaction {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
get keys(): Array<PublicKey> {
|
get keys(): Array<PublicKey> {
|
||||||
assert(this.instructions.length === 1);
|
invariant(this.instructions.length === 1);
|
||||||
return this.instructions[0].keys;
|
return this.instructions[0].keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +310,7 @@ export class Transaction {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
get programId(): PublicKey {
|
get programId(): PublicKey {
|
||||||
assert(this.instructions.length === 1);
|
invariant(this.instructions.length === 1);
|
||||||
return this.instructions[0].programId;
|
return this.instructions[0].programId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +319,7 @@ export class Transaction {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
get userdata(): Buffer {
|
get userdata(): Buffer {
|
||||||
assert(this.instructions.length === 1);
|
invariant(this.instructions.length === 1);
|
||||||
return this.instructions[0].userdata;
|
return this.instructions[0].userdata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,14 @@ import type {TransactionSignature} from '../transaction';
|
||||||
*/
|
*/
|
||||||
export async function sendAndConfirmTransaction(
|
export async function sendAndConfirmTransaction(
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
from: Account,
|
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
runtimeErrorOk: boolean = false,
|
...signers: Array<Account>
|
||||||
): Promise<?TransactionSignature> {
|
): Promise<?TransactionSignature> {
|
||||||
let sendRetries = 10;
|
let sendRetries = 10;
|
||||||
let signature;
|
let signature;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
signature = await connection.sendTransaction(from, transaction);
|
signature = await connection.sendTransaction(transaction, ...signers);
|
||||||
|
|
||||||
// Wait up to a couple seconds for a confirmation
|
// Wait up to a couple seconds for a confirmation
|
||||||
let status = 'SignatureNotFound';
|
let status = 'SignatureNotFound';
|
||||||
|
@ -41,10 +40,7 @@ export async function sendAndConfirmTransaction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (status === 'Confirmed') {
|
||||||
status === 'Confirmed' ||
|
|
||||||
(status === 'ProgramRuntimeError' && runtimeErrorOk)
|
|
||||||
) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,5 +31,5 @@ test('load BPF program', async () => {
|
||||||
keys: [from.publicKey],
|
keys: [from.publicKey],
|
||||||
programId,
|
programId,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, from, transaction);
|
await sendAndConfirmTransaction(connection, transaction, from);
|
||||||
});
|
});
|
||||||
|
|
|
@ -353,7 +353,7 @@ test('transaction', async () => {
|
||||||
accountTo.publicKey,
|
accountTo.publicKey,
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
const signature = await connection.sendTransaction(accountFrom, transaction);
|
const signature = await connection.sendTransaction(transaction, accountFrom);
|
||||||
|
|
||||||
mockRpc.push([
|
mockRpc.push([
|
||||||
url,
|
url,
|
||||||
|
@ -448,7 +448,7 @@ test('multi-instruction transaction', async () => {
|
||||||
10,
|
10,
|
||||||
).add(SystemProgram.move(accountTo.publicKey, accountFrom.publicKey, 10));
|
).add(SystemProgram.move(accountTo.publicKey, accountFrom.publicKey, 10));
|
||||||
|
|
||||||
const signature = await connection.sendTransaction(accountFrom, transaction);
|
const signature = await connection.sendTransaction(transaction, accountFrom, accountTo);
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (await connection.confirmTransaction(signature)) {
|
if (await connection.confirmTransaction(signature)) {
|
||||||
|
@ -492,7 +492,7 @@ test('account change notification', async () => {
|
||||||
3,
|
3,
|
||||||
BpfLoader.programId,
|
BpfLoader.programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, owner, transaction);
|
await sendAndConfirmTransaction(connection, transaction, owner);
|
||||||
|
|
||||||
const loader = new Loader(connection, BpfLoader.programId);
|
const loader = new Loader(connection, BpfLoader.programId);
|
||||||
await loader.load(programAccount, [1, 2, 3]);
|
await loader.load(programAccount, [1, 2, 3]);
|
||||||
|
|
|
@ -29,5 +29,5 @@ test('load native program', async () => {
|
||||||
programId,
|
programId,
|
||||||
});
|
});
|
||||||
|
|
||||||
await sendAndConfirmTransaction(connection, from, transaction);
|
await sendAndConfirmTransaction(connection, transaction, from);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue