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

feat(simulated_transaction): Add Inner Instructions #2756

Merged
merged 8 commits into from
Jun 29, 2024

Conversation

0xIchigo
Copy link
Contributor

This PR aims to address the issue I've outlined in #2755 where the innerInstructions parameter is missing for transaction simulations

Copy link

changeset-bot bot commented May 31, 2024

⚠️ No Changeset found

Latest commit: 8c9ee5f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@mergify mergify bot added the community label May 31, 2024
@mergify mergify bot requested a review from a team May 31, 2024 16:31
Copy link
Contributor

@mcintyre94 mcintyre94 left a comment

Choose a reason for hiding this comment

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

Thanks for this! I haven't tested this as an RPC call yet, but comparing to the RPC docs there seem to be some differences here

I'm guessing that some of this is that jsonParsed encoding can produce decoded inner instructions, and the docs are missing that. But the field names also seem to differ from the docs a bit.

Do you by any chance have any example simulateTransaction calls you've been testing with that I could use to review this a bit better?

packages/library-legacy/src/connection.ts Outdated Show resolved Hide resolved
packages/library-legacy/src/connection.ts Show resolved Hide resolved
packages/library-legacy/src/connection.ts Show resolved Hide resolved
@0xIchigo
Copy link
Contributor Author

@mcintyre94 ah that's my bad! I was trying to reuse the ParsedInstruction and PartiallyDecodedInstruction types, but I think I'm better off creating an entirely new type. I'll refactor the PR to address those changes

@0xIchigo 0xIchigo requested a review from mcintyre94 May 31, 2024 20:42
Copy link
Contributor

@mcintyre94 mcintyre94 left a comment

Choose a reason for hiding this comment

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

Thanks for updating this! I'm still a little confused about how some of the Rust enums map to these data structures. But I might be interpreting things wrong, and I don't have an RPC that can test this atm.

packages/library-legacy/src/connection.ts Outdated Show resolved Hide resolved
packages/library-legacy/src/connection.ts Outdated Show resolved Hide resolved

export type ParsedNewInnerInstruction = {
index: number;
instructions: UiInstruction[];
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure where this comes from, but can we just re-use UiInnerInstructions?

packages/library-legacy/src/connection.ts Show resolved Hide resolved
packages/library-legacy/src/connection.ts Outdated Show resolved Hide resolved
@steveluscher
Copy link
Collaborator

steveluscher commented Jun 17, 2024

Do you have time to knock this out @0xIchigo, or would you like us to finish it up?

@0xIchigo
Copy link
Contributor Author

gm @steveluscher ! Totally up to you — I was waiting for us (i.e., Helius) to update our fleet to 1.18 so I could run some sample transactions to see the correct responses

@mcintyre94
Copy link
Contributor

mcintyre94 commented Jun 19, 2024

Example of an unparsed inner instruction:

 "innerInstructions": [
        {
            "index": 0,
            "instructions": [
                {
                    "accounts": [
                        "9hUi6B4rqntMzvEz6HKTv9MAq2KJ7s3FvBxHBFf2WkS7",
                        "7Qpk9MmLevLeCKZqLQRfiucfR7P13XGtMhu7z5fbw3jN",
                        "8oxdgaw4EzgAVsisY1hhuZpTP3TLgkNYx7o1FrJwPfrs",
                        "Fo36995qyeK9n7sc7bxTTLgiPCQGukExGTvLdWRs5n68",
                        "J8x6y5G7GmTkuKTbbCAnfhn72vaUU2qsB6je9oKFigHM",
                        "CzK26LWpoU9UjSrZkVu97oZj63abJrNv1zp9Hy2zZdy5",
                        "AVNMK6wiGfppdQNg9WKfMRBXefDPGZFh2f3o1fRbgN8n"
                    ],
                    "data": "19TzxKPM1",
                    "programId": "zDEXqXEG7gAyxb1Kg9mK5fPnUdENCGKzWrM21RMdWRq",
                    "stackHeight": 2
                }
            ]
        }
    ]

Modified the simulate transaction call on https://explorer.solana.com/tx/5f47YKxsAmZV31QmFmVH8vHY9zdChAEJTKw2cc1nX8tdZ6XTTWdctevBLiCGncbTYqfL3LZZLHTwUBWCkHjyDCs5/inspect to pass "innerInstructions": true as a param.

And one where some are parsed:

    "innerInstructions": [
        {
            "index": 4,
            "instructions": [
                {
                    "parsed": {
                        "info": {
                            "lamports": 1113600,
                            "newAccount": "GhVgUsQ2N4ttchFFtMwtdjCiSRgQwAM2eUotWDA1ADQe",
                            "owner": "3tZPEagumHvtgBhivFJCmhV9AyhBHGW9VgdsK52i4gwP",
                            "source": "25xPxkziuZzKbcTxYHYRQq5gzA4SN4xVHnQN2UKktTNY",
                            "space": 32
                        },
                        "type": "createAccount"
                    },
                    "program": "system",
                    "programId": "11111111111111111111111111111111",
                    "stackHeight": 2
                }
            ]
        },
        {
            "index": 5,
            "instructions": [
                {
                    "accounts": [
                        "G5FEXmMK9QgUYheS9DADpVbAMSWex5TD3YbCVj4sreoZ",
                        "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
                        "3YMPvTLn5C2oLh6vRGMgxGsDGJGFLZz92hwoYT4qnEzA",
                        "ChpcDw3SwjUoai9xdTvTn9ju1QcK44GE9Cp2g9uYSMqP",
                        "HkKorCHbaWAQRLqUJkwdBD5HaMGJZpD6rENUC7hWhPgp",
                        "7W87mhpyasAcW77ki2bf2Qs3gqUNgYKR8hVHczYETmUA",
                        "Ap4DHrnVybF2wXoKxBdFEEJ1Yew8KhZtMUShusHfpump",
                        "So11111111111111111111111111111111111111112",
                        "BUG68ajmw4twTgL8yif8vaK23oZUf3XM7zRLgSazEWfd",
                        "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
                        "25xPxkziuZzKbcTxYHYRQq5gzA4SN4xVHnQN2UKktTNY",
                        "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                        "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                        "D1ZN9Wj1fRSUQfCjhvnu1hqDMT7hzjzBBpi12nVniYD6",
                        "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
                        "2yXR2ybQHRgqtAC51WwKZnNt5gjNZR78AWsT5EzY4uFc",
                        "31BCwmmHVbGQVPYFrWsHby4yYaS2PtBojhAoWfjfeh18"
                    ],
                    "data": "PgQWtn8ozix5ipTqV4Ms6sCsUo4prGBqq",
                    "programId": "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
                    "stackHeight": 2
                },
                {
                    "parsed": {
                        "info": {
                            "authority": "25xPxkziuZzKbcTxYHYRQq5gzA4SN4xVHnQN2UKktTNY",
                            "destination": "ChpcDw3SwjUoai9xdTvTn9ju1QcK44GE9Cp2g9uYSMqP",
                            "mint": "So11111111111111111111111111111111111111112",
                            "source": "HkKorCHbaWAQRLqUJkwdBD5HaMGJZpD6rENUC7hWhPgp",
                            "tokenAmount": {
                                "amount": "2534011000",
                                "decimals": 9,
                                "uiAmount": 2.534011,
                                "uiAmountString": "2.534011"
                            }
                        },
                        "type": "transferChecked"
                    },
                    "program": "spl-token",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                    "stackHeight": 3
                },
                {
                    "parsed": {
                        "info": {
                            "authority": "G5FEXmMK9QgUYheS9DADpVbAMSWex5TD3YbCVj4sreoZ",
                            "destination": "7W87mhpyasAcW77ki2bf2Qs3gqUNgYKR8hVHczYETmUA",
                            "mint": "Ap4DHrnVybF2wXoKxBdFEEJ1Yew8KhZtMUShusHfpump",
                            "source": "3YMPvTLn5C2oLh6vRGMgxGsDGJGFLZz92hwoYT4qnEzA",
                            "tokenAmount": {
                                "amount": "142226232988",
                                "decimals": 6,
                                "uiAmount": 142226.232988,
                                "uiAmountString": "142226.232988"
                            }
                        },
                        "type": "transferChecked"
                    },
                    "program": "spl-token",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                    "stackHeight": 3
                },
                {
                    "accounts": [
                        "D1ZN9Wj1fRSUQfCjhvnu1hqDMT7hzjzBBpi12nVniYD6"
                    ],
                    "data": "yCGxBopjnVNQkNP5usq1PpL4UxKhD69eFHE2ykhVSYEW1RYvu29Da84bmMAS91uZi91DepyEwaRqreBR29yi5zgRawHA9bi14c8p1zXvrAuNPRGPcHWqx6cc9ynUkxHo2fMTAoaSf9MNjxWaPhEQzr4CLk2pkMAwx75n6Kq8TqW34sN5fKNkSMewSvW8PffqjpCdJo",
                    "programId": "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
                    "stackHeight": 3
                },
                {
                    "accounts": [
                        "D8cy77BBepLMngZx6ZukaTff5hCt1HrWyKk3Hnd9oitf"
                    ],
                    "data": "QMqFu4fYGGeUEysFnenhAvBobXTzswhLdvQq6s8axxcbKUPRksm2543pJNNNHVd1VJ58FCg7NVh9cMuPYiMKNyfUpUXSDci9arMkqVwgC1zp935dMUGSepSh5bZikjbvpZ41sHjcBwBzZAWBVgSW2FyzQnW8MeaUQwcWk3AgrveSRxK",
                    "programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
                    "stackHeight": 2
                },
                {
                    "accounts": [
                        "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "8kFrDne6y1E9Wnebs7xS6eXJYHoVF43AfPUwGzd1gEmB",
                        "8nrYAQAfTysFpq1g59P4yTPJupCwFcWDjhqLaQPpJwWM",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "9tNgYNmgf8XCEyvMEXgRwGUPXMyLYbtQScvXGsxXWWZi",
                        "7W87mhpyasAcW77ki2bf2Qs3gqUNgYKR8hVHczYETmUA",
                        "HkKorCHbaWAQRLqUJkwdBD5HaMGJZpD6rENUC7hWhPgp",
                        "25xPxkziuZzKbcTxYHYRQq5gzA4SN4xVHnQN2UKktTNY"
                    ],
                    "data": "6EnMsN5NnnGB5MyfVDN6QrK",
                    "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
                    "stackHeight": 2
                },
                {
                    "parsed": {
                        "info": {
                            "amount": "142226232988",
                            "authority": "25xPxkziuZzKbcTxYHYRQq5gzA4SN4xVHnQN2UKktTNY",
                            "destination": "8nrYAQAfTysFpq1g59P4yTPJupCwFcWDjhqLaQPpJwWM",
                            "source": "7W87mhpyasAcW77ki2bf2Qs3gqUNgYKR8hVHczYETmUA"
                        },
                        "type": "transfer"
                    },
                    "program": "spl-token",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                    "stackHeight": 3
                },
                {
                    "parsed": {
                        "info": {
                            "amount": "2477814592",
                            "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1",
                            "destination": "HkKorCHbaWAQRLqUJkwdBD5HaMGJZpD6rENUC7hWhPgp",
                            "source": "8kFrDne6y1E9Wnebs7xS6eXJYHoVF43AfPUwGzd1gEmB"
                        },
                        "type": "transfer"
                    },
                    "program": "spl-token",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                    "stackHeight": 3
                },
                {
                    "accounts": [
                        "D8cy77BBepLMngZx6ZukaTff5hCt1HrWyKk3Hnd9oitf"
                    ],
                    "data": "QMqFu4fYGGeUEysFnenhAvR83g86EDDNxzUskfkWKYCBPWe1hqgD6jgKAXr6aYoEQcUmTdi3nY764YdkSkiXjff4uA11bvtJxVE4Dj5zeTT5auuSofAuhBY9jUzKZyH9F5Z165NjVh9gmVHijhjXS5sUt3WVQKYUBcnaLngEDbXm4AB",
                    "programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
                    "stackHeight": 2
                }
            ]
        }
    ]

From https://explorer.solana.com/tx/4uDi5TXxwB1bGWaecZia1w4nseb6A623Bd8zmcEh1mMeU8SqhGGDhYFxqnbWYyjo9s9ofboxWJuhWjhJiCM2Duzb/inspect

So I think the types are basically (pseudocode):

type UnparsedInnerInstruction = {
  accounts: Address[],
  data: Base58EncodedString,
  programId: Address,
  stackHeight: number
}

type ParsedInnerInstruction = {
  parsed: {
    info: any,
    type: string // or enum if we can find the values?
  },
  program: string, // or enum if we can find the values?
  programId: Address,
  stackHeight: number
}

type InnerInstructions = (UnparsedInnerInstruction | ParsedInnerInstruction)[]

@mcintyre94
Copy link
Contributor

@0xIchigo Sorry for all the back and forth here, I should have looked into this more closely before. We can make this PR much simpler, we don't need to define any new types.

The reason for the type errors you're getting is because the existing ParsedTransactionMeta has innerInstructions?: ParsedInnerInstruction[] | null;, and this is eventually using the UiInnerInstruction type that's been modified. The changes in this PR are incompatible.

But if you do getTransaction with the example transactions I posted above and jsonParsed encoding, you'll see that their result.meta.innerInstructions is identical to the inner instructions I posted above from simulating them. So we should just re-use those types exactly, ie probably just add innerInstructions?: ParsedInnerInstruction[] | null; to the simulate output.

The relevant types already defined here are:

export type ParsedInnerInstruction = {
  index: number;
  instructions: (ParsedInstruction | PartiallyDecodedInstruction)[];
};

export type ParsedInstruction = {
  /** Name of the program for this instruction */
  program: string;
  /** ID of the program for this instruction */
  programId: PublicKey;
  /** Parsed instruction info */
  parsed: any;
};

export type PartiallyDecodedInstruction = {
  /** Program id called by this instruction */
  programId: PublicKey;
  /** Public keys of accounts passed to this instruction */
  accounts: Array<PublicKey>;
  /** Raw base-58 instruction data */
  data: string;
};

This is exactly what we're seeing in practice from the simulateTransaction with innerInstructions on 1.18

Given the types are exactly the same, let's just re-use them. I think you can exactly re-use from ParsedTransactionMeta too:

  /** An array of cross program invoked parsed instructions */
  innerInstructions?: ParsedInnerInstruction[] | null;

@0xIchigo
Copy link
Contributor Author

0xIchigo commented Jun 20, 2024

Ahhh that's my bad for overcomplicating things — should be all good now! cc @steveluscher @mcintyre94

@0xIchigo 0xIchigo requested a review from mcintyre94 June 20, 2024 18:01
packages/library-legacy/src/connection.ts Outdated Show resolved Hide resolved
@steveluscher steveluscher force-pushed the fix/add-inner-instructions branch from ad23ff4 to be1b4f4 Compare June 24, 2024 19:31
@steveluscher steveluscher force-pushed the fix/add-inner-instructions branch from be1b4f4 to 8c9ee5f Compare June 28, 2024 20:57
@steveluscher steveluscher added the automerge Merge this Pull Request automatically once CI passes label Jun 28, 2024
@steveluscher steveluscher merged commit 0936673 into solana-labs:master Jun 29, 2024
6 checks passed
Copy link
Contributor

🎉 This PR is included in version 1.94.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Copy link
Contributor

Because there has been no activity on this PR for 14 days since it was merged, it has been automatically locked. Please open a new issue if it requires a follow up.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
automerge Merge this Pull Request automatically once CI passes community released
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants