solanaj - invalid transaction: Transaction failed to sanitize accounts offsets correctly

Viewed 345

I'm using solanaj (Java sdk for solana) and trying to write hello-world example of solana-labs but getting this error on sendTransaction() 'invalid transaction: Transaction failed to sanitize accounts offsets correctly'. There is no additional information in the error about what I'm passing wrong. Can someone help me, here is my Java code: ''' //establishConnection RpcClient client = new RpcClient("http://127.0.0.1:8899");

    //establishPayer
    Long fee = Long.valueOf(0);
    FeeCalculatorInfo feeCalculatorInfo = client.getApi().getFeeCalculatorForBlockhash(client.getApi().getRecentBlockhash());

    fee += client.getApi().getMinimumBalanceForRentExemption(greetingMessageSize);
    fee += feeCalculatorInfo.getValue().getFeeCalculator().getLamportsPerSignature() * 100;

    if (payee == null) {
        try {
            String str = Files.readString(payeePath, StandardCharsets.UTF_8);
            Gson gson = new Gson();
            byte[] parsed = gson.fromJson(str, byte[].class);
            payee = TweetNaclFast.Signature.keyPair_fromSecretKey(parsed);
            payeePubKey = new PublicKey(payee.getPublicKey());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    Long lamportBalance = client.getApi().getBalance(payeePubKey);

    if (lamportBalance < fee) {
        String sign = client.getApi().requestAirdrop(payeePubKey, fee - lamportBalance);
        ConfirmedTransaction confirmedTransaction = client.getApi().getConfirmedTransaction(sign);
    }
    Long lamportBalanceUpdated = client.getApi().getBalance(payeePubKey);

    //checkProgram
    try {
        String str = Files.readString(programIdPath, StandardCharsets.UTF_8);
        Gson gson = new Gson();
        byte[] parsed = gson.fromJson(str, byte[].class);
        programKeyPair = TweetNaclFast.Signature.keyPair_fromSecretKey(parsed);
        programId = new PublicKey(programKeyPair.getPublicKey());
    } catch (IOException e) {
        e.printStackTrace();
    }
    AccountInfo programAccountInfo = client.getApi().getAccountInfo(programId);

    String greetingSeed = "hellogreetingtoyou";
    PublicKey greetingPubKey = null;
    try {
        greetingPubKey = PublicKey.createProgramAddress(Collections.singletonList(greetingSeed.getBytes()), programId);
    } catch (Exception e) {
        e.printStackTrace();
    }

    Account signer = new Account(payee.getSecretKey());
    AccountInfo greetingAccountInfo = client.getApi().getAccountInfo(greetingPubKey);
    if (greetingAccountInfo.getValue() == null) {
        Transaction transaction = new Transaction();
        long lamports = client.getApi().getMinimumBalanceForRentExemption(greetingMessageSize);

        transaction.addInstruction(SystemProgram.createAccount(payeePubKey, greetingPubKey, lamports,
                greetingMessageSize, PROGRAM_ID));

        String signature = client.getApi().sendTransaction(transaction, signer);

    }

'''

1 Answers

The program is mixing two separate concepts, creating accounts at the transaction level by adding SystemProgram.createAccount to your transaction, and creating PDA accounts using invoke_signed from within your program.

When trying to add SystemProgram.createAccount(payeePubkey, greetingPubkey,...), the transaction expects a signature from greetingPubkey, but only payeePubkey has signed, causing the error.

The easiest way to resolve this problem is to not use a program address for greetingPubkey, and instead do something like:

Account signer = new Account(payee.getSecretKey());
KeyPair greeting = TweetNaclFast.Signature.keyPair();
Account greetingSigner = new Account(greeting.getSecretKey());
PublicKey greetingPubkey = new PublicKey(greeting.getPublicKey())
Transaction transaction = new Transaction();
long lamports = client.getApi().getMinimumBalanceForRentExemption(greetingMessageSize);

transaction.addInstruction(SystemProgram.createAccount(payeePubKey, greetingPubKey, lamports, greetingMessageSize, PROGRAM_ID));

String signature = client.getApi().sendTransaction(transaction, signer, greetingSigner);

Note that I haven't tried to compile this!

Related