I found a Design Issue when using solana and anchor...
zilinissleepin opened this issue · comments
intro
I am working for using my own deployed program to swap in DEXs such as orca using anchorpy and solana-py.
But I have found that when I create a instruction with my program, there will be an Error: InvalidParamsMessage { message: "invalid transaction: Transaction failed to sanitize accounts offsets correctly" }
this is my client code:
async def update_owner(new_owner: Pubkey, owner: Keypair):
acc = await AccessControl.fetch(provider.connection, pda[0])
print(f"The owner will change from {acc.only_owner} to {new_owner}")
ix = instructions.update_owner({
"new_owner": new_owner,
}, {
"access_control": pda[0],
"only_owner": owner.pubkey()
})
recent_blockhash = await provider.connection.get_latest_blockhash(commitment="finalized")
tx = Transaction(recent_blockhash=recent_blockhash.value.blockhash).add(ix)
tx.sign(owner)
print(await provider.simulate(tx))
pda
is a PDA address that stores some Access Control Infos.
only_owner
is a read-only account that must be signed.
instructions.update_owner
is a piece of auto-generated code by anchorpy.
class UpdateOwnerAccounts(typing.TypedDict):
access_control: Pubkey
only_owner: Pubkey
def update_owner(
args: UpdateOwnerArgs,
accounts: UpdateOwnerAccounts,
program_id: Pubkey = PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> Instruction:
keys: list[AccountMeta] = [
AccountMeta(
pubkey=accounts["access_control"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["only_owner"], is_signer=True, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xa4\xbc|\xfe\x84\x1a\xc6\xb2"
encoded_args = layout.build(
{
"new_owner": args["new_owner"],
}
)
data = identifier + encoded_args
return Instruction(program_id, data, keys)
Therefore, I will include 3 accounts: access_control pda, only_owner account and a transaction payer. But I set the payer the same as the only_owner account. So there will be 2 accounts.
I found that when I run this client code, I will get an error InvalidParamsMessage { message: "invalid transaction: Transaction failed to sanitize accounts offsets correctly" }
.
I dive deep and find that the MessageHeader builds incorrectly in solders pacakage. the MessageHeader is header: MessageHeader { num_required_signatures: 1, num_readonly_signed_accounts: 1, num_readonly_unsigned_accounts: 1 }
num_readonly_signed_accounts is 0 not 1, because the only_owner account will be the transaction payer and become writable. However, it seems that the solder and solana SDK does not effectively address this issue.
I have found that the root reason is at tx = Transaction(recent_blockhash=recent_blockhash.value.blockhash).add(ix)
, Transaction init must clarify the fee_payer
, otherwise, the fee_payer will be set to None and cause the Sanitize Error.
But I have clarified the payer already when init the provider.
This is maybe a SDK Design Issue?