Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for returnData in simulate transaction #26499

Merged
merged 1 commit into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion web3.js/src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -711,13 +711,20 @@ export type SimulatedTransactionAccountInfo = {
rentEpoch?: number;
};

export type TransactionReturnDataEncoding = 'base64';

export type TransactionReturnData = {
programId: string;
data: [string, TransactionReturnDataEncoding];
};

export type SimulatedTransactionResponse = {
err: TransactionError | string | null;
logs: Array<string> | null;
accounts?: (SimulatedTransactionAccountInfo | null)[] | null;
unitsConsumed?: number;
returnData?: TransactionReturnData | null;
};

const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(
pick({
err: nullable(union([pick({}), string()])),
Expand All @@ -738,6 +745,14 @@ const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(
),
),
unitsConsumed: optional(number()),
returnData: optional(
nullable(
pick({
programId: string(),
data: tuple([string(), literal('base64')]),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to hard code base64 here since TransactionReturnDataEncoding is a type and was giving error, don't know if there is any way to avoid this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can eventually use some other type, but no problem with doing that here

}),
),
),
}),
);

Expand Down
19 changes: 19 additions & 0 deletions web3.js/test/bpf-loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,25 @@ if (process.env.TEST_LIVE) {
);
});

it('simulate transaction with returnData', async () => {
const simulatedTransaction = new Transaction().add({
keys: [
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
],
programId: program.publicKey,
});
const {err, returnData} = (
await connection.simulateTransaction(simulatedTransaction, [
payerAccount,
])
).value;
const expectedReturnData = new Uint8Array([1, 2, 3]);
var decodedData = Buffer.from(returnData.data[0], returnData.data[1]);
expect(err).to.be.null;
expect(returnData.programId).to.eql(program.publicKey.toString());
expect(decodedData).to.eql(expectedReturnData);
});
atharmohammad marked this conversation as resolved.
Show resolved Hide resolved

it('deprecated - simulate transaction without signature verification', async () => {
const simulatedTransaction = new Transaction().add({
keys: [
Expand Down
47 changes: 47 additions & 0 deletions web3.js/test/connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3756,6 +3756,53 @@ describe('Connection', function () {
verifySignatureStatus(response, expectedErr);
});

if (mockServer) {
it('returnData on simulateTransaction', async () => {
const tx = new Transaction();
tx.feePayer = Keypair.generate().publicKey;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joncinque It's worth noting that this will only work with a funded feePayer, which makes simulation somewhat problematic for second-order return-data apis. That doesn't need to hold up anything here, but just something to think about for usage and documentation purposes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah true, I was thinking we could at least support it in its current state and improve on it later. Just to be totally clear, when you say "that doesn't need to hold up anything here", do you mean that you're ok with the approach?

Also, did we ever come up with a model for simulating transactions without a funded fee payer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I’m fine with this approach.
No, we haven’t designed implemented a way to bypass fee-payer check in simulation


const getLatestBlockhashResponse = {
method: 'getLatestBlockhash',
params: [],
value: {
blockhash: 'CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR',
feeCalculator: {
lamportsPerSignature: 5000,
},
lastValidBlockHeight: 51,
},
withContext: true,
};
const simulateTransactionResponse = {
method: 'simulateTransaction',
params: [],
value: {
err: null,
accounts: null,
logs: [
'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri invoke [1]',
'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri consumed 2366 of 1400000 compute units',
'Program return: 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri KgAAAAAAAAA=',
'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success',
],
returnData: {
data: ['KgAAAAAAAAA==', 'base64'],
programId: '83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri',
},
unitsConsumed: 2366,
},
withContext: true,
};
await mockRpcResponse(getLatestBlockhashResponse);
await mockRpcResponse(simulateTransactionResponse);
const response = (await connection.simulateTransaction(tx)).value;
expect(response.returnData).to.eql({
data: ['KgAAAAAAAAA==', 'base64'],
programId: '83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri',
});
});
}

if (process.env.TEST_LIVE) {
it('simulate transaction with message', async () => {
connection._commitment = 'confirmed';
Expand Down
Binary file modified web3.js/test/fixtures/noop-program/solana_bpf_rust_noop.so
Binary file not shown.
9 changes: 8 additions & 1 deletion web3.js/test/fixtures/noop-program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Example Rust-based BPF program that prints out the parameters passed to it
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, log::*, msg, pubkey::Pubkey,
account_info::AccountInfo, entrypoint::ProgramResult, log::*, msg, program::set_return_data,
pubkey::Pubkey,
};

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -55,6 +56,12 @@ fn process_instruction(
panic!();
}

{
// return data in simulate transaction
let return_data: &[u8] = &[1, 2, 3];
set_return_data(return_data);
}

Ok(())
}

Expand Down