From f83f95b9b484b06495456d592659a1c90eb0448a Mon Sep 17 00:00:00 2001 From: b1acksun Date: Thu, 19 Aug 2021 10:31:49 +0300 Subject: [PATCH] fix: account keys order --- .../org/p2p/solanaj/core/AccountKeysList.java | 45 +++++++++-------- .../org/p2p/solanaj/core/AccountMeta.java | 12 +++++ .../java/org/p2p/solanaj/core/Message.java | 27 +++++----- .../p2p/solanaj/core/AccountKeysListTest.java | 49 +++++++++++++++++++ 4 files changed, 99 insertions(+), 34 deletions(-) create mode 100644 src/test/java/org/p2p/solanaj/core/AccountKeysListTest.java diff --git a/src/main/java/org/p2p/solanaj/core/AccountKeysList.java b/src/main/java/org/p2p/solanaj/core/AccountKeysList.java index 27f87c49..4b588c1b 100644 --- a/src/main/java/org/p2p/solanaj/core/AccountKeysList.java +++ b/src/main/java/org/p2p/solanaj/core/AccountKeysList.java @@ -3,39 +3,42 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; -import java.util.HashMap; +import java.util.List; public class AccountKeysList { - private HashMap accounts; + private List accountsList; public AccountKeysList() { - accounts = new HashMap(); + accountsList = new ArrayList(); } public void add(AccountMeta accountMeta) { - String key = accountMeta.getPublicKey().toString(); - - if (accounts.containsKey(key)) { - if ((!accounts.get(key).isWritable() && accountMeta.isWritable()) - || (!accounts.get(key).isSigner() && accountMeta.isSigner())) { - accounts.put(key, accountMeta); - } - } else { - accounts.put(key, accountMeta); - } + accountsList.add(accountMeta); } public void addAll(Collection metas) { - for (AccountMeta meta : metas) { - add(meta); - } + accountsList.addAll(metas); } - public ArrayList getList() { - ArrayList accountKeysList = new ArrayList(accounts.values()); - accountKeysList.sort(metaComparator); + public List getList() { + ArrayList uniqueMetas = new ArrayList(); + + for (AccountMeta accountMeta : accountsList) { + PublicKey pubKey = accountMeta.getPublicKey(); + + int index = AccountMeta.findAccountIndex(uniqueMetas, pubKey); + if (index > -1) { + uniqueMetas.set(index, + new AccountMeta(pubKey, accountsList.get(index).isSigner() || accountMeta.isSigner(), + accountsList.get(index).isWritable() || accountMeta.isWritable())); + } else { + uniqueMetas.add(accountMeta); + } + } + + uniqueMetas.sort(metaComparator); - return accountKeysList; + return uniqueMetas; } private static final Comparator metaComparator = new Comparator() { @@ -53,7 +56,7 @@ public int compare(AccountMeta am1, AccountMeta am2) { return cmpkWritable; } - return Integer.compare(cmpSigner, cmpkWritable); + return 0; } }; diff --git a/src/main/java/org/p2p/solanaj/core/AccountMeta.java b/src/main/java/org/p2p/solanaj/core/AccountMeta.java index fdc7a98f..da51f895 100644 --- a/src/main/java/org/p2p/solanaj/core/AccountMeta.java +++ b/src/main/java/org/p2p/solanaj/core/AccountMeta.java @@ -1,5 +1,7 @@ package org.p2p.solanaj.core; +import java.util.List; + public class AccountMeta { private PublicKey publicKey; private boolean isSigner; @@ -22,4 +24,14 @@ public boolean isSigner() { public boolean isWritable() { return isWritable; } + + public static int findAccountIndex(List accountMetaList, PublicKey key) { + for (int i = 0; i < accountMetaList.size(); i++) { + if (accountMetaList.get(i).getPublicKey().equals(key)) { + return i; + } + } + + return -1; + } } \ No newline at end of file diff --git a/src/main/java/org/p2p/solanaj/core/Message.java b/src/main/java/org/p2p/solanaj/core/Message.java index 93c86dae..384f5d72 100644 --- a/src/main/java/org/p2p/solanaj/core/Message.java +++ b/src/main/java/org/p2p/solanaj/core/Message.java @@ -41,17 +41,22 @@ int getLength() { private AccountKeysList accountKeys; private List instructions; private PublicKey feePayer; + private List programIds; public Message() { + this.programIds = new ArrayList(); this.accountKeys = new AccountKeysList(); this.instructions = new ArrayList(); } public Message addInstruction(TransactionInstruction instruction) { accountKeys.addAll(instruction.getKeys()); - accountKeys.add(new AccountMeta(instruction.getProgramId(), false, false)); instructions.add(instruction); + if (!programIds.contains(instruction.getProgramId().toBase58())) { + programIds.add(instruction.getProgramId().toBase58()); + } + return this; } @@ -71,6 +76,9 @@ public byte[] serialize() { messageHeader = new MessageHeader(); + for (String programId : programIds) { + accountKeys.add(new AccountMeta(new PublicKey(programId), false, false)); + } List keysList = getAccountKeys(); int accountKeysSize = keysList.size(); @@ -84,11 +92,13 @@ public byte[] serialize() { byte[] keyIndices = new byte[keysSize]; for (int i = 0; i < keysSize; i++) { - keyIndices[i] = (byte) findAccountIndex(keysList, instruction.getKeys().get(i).getPublicKey()); + keyIndices[i] = (byte) AccountMeta.findAccountIndex(keysList, + instruction.getKeys().get(i).getPublicKey()); } CompiledInstruction compiledInstruction = new CompiledInstruction(); - compiledInstruction.programIdIndex = (byte) findAccountIndex(keysList, instruction.getProgramId()); + compiledInstruction.programIdIndex = (byte) AccountMeta.findAccountIndex(keysList, + instruction.getProgramId()); compiledInstruction.keyIndicesCount = ShortvecEncoding.encodeLength(keysSize); compiledInstruction.keyIndices = keyIndices; compiledInstruction.dataLength = ShortvecEncoding.encodeLength(instruction.getData().length); @@ -148,7 +158,7 @@ protected void setFeePayer(PublicKey feePayer) { private List getAccountKeys() { List keysList = accountKeys.getList(); - int feePayerIndex = findAccountIndex(keysList, feePayer); + int feePayerIndex = AccountMeta.findAccountIndex(keysList, feePayer); List newList = new ArrayList(); @@ -164,13 +174,4 @@ private List getAccountKeys() { return newList; } - private int findAccountIndex(List accountMetaList, PublicKey key) { - for (int i = 0; i < accountMetaList.size(); i++) { - if (accountMetaList.get(i).getPublicKey().equals(key)) { - return i; - } - } - - return -1; - } } diff --git a/src/test/java/org/p2p/solanaj/core/AccountKeysListTest.java b/src/test/java/org/p2p/solanaj/core/AccountKeysListTest.java new file mode 100644 index 00000000..779e07a6 --- /dev/null +++ b/src/test/java/org/p2p/solanaj/core/AccountKeysListTest.java @@ -0,0 +1,49 @@ +package org.p2p.solanaj.core; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.p2p.solanaj.programs.SystemProgram; + +public class AccountKeysListTest { + + @Test + public void getSortedList() { + AccountKeysList list = new AccountKeysList(); + + list.addAll( + Arrays.asList(new AccountMeta(new PublicKey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"), true, true), + new AccountMeta(new PublicKey("7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7"), false, true), + new AccountMeta(new PublicKey("HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds"), false, false), + new AccountMeta(new PublicKey("6Cust2JhvweKLh4CVo1dt21s2PJ86uNGkziudpkNPaCj"), false, false), + new AccountMeta(SystemProgram.PROGRAM_ID, false, false), + new AccountMeta(new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), false, false), + new AccountMeta(Sysvar.SYSVAR_RENT_ADDRESS, false, false), + new AccountMeta(new PublicKey("8VBafTNv1F8k5Bg7DTVwhitw3MGAMTmekHsgLuMJxLC8"), false, false), + new AccountMeta(new PublicKey("8VBafTNv1F8k5Bg7DTVwhitw3MGAMTmekHsgLuMJxLC8"), false, true), + new AccountMeta(new PublicKey("6Cust2JhvweKLh4CVo1dt21s2PJ86uNGkziudpkNPaCj"), false, false), + new AccountMeta(new PublicKey("7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7"), false, true), + new AccountMeta(new PublicKey("3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT"), false, false), + new AccountMeta(new PublicKey("3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT"), true, false), + new AccountMeta(new PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), false, false), + new AccountMeta(new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), false, false))); + + List accountKeysList = list.getList(); + + assertEquals(10, accountKeysList.size()); + + assertEquals("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3", accountKeysList.get(0).getPublicKey().toBase58()); + assertEquals("3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT", accountKeysList.get(1).getPublicKey().toBase58()); + assertEquals("7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7", accountKeysList.get(2).getPublicKey().toBase58()); + assertEquals("8VBafTNv1F8k5Bg7DTVwhitw3MGAMTmekHsgLuMJxLC8", accountKeysList.get(3).getPublicKey().toBase58()); + assertEquals("HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds", accountKeysList.get(4).getPublicKey().toBase58()); + assertEquals("6Cust2JhvweKLh4CVo1dt21s2PJ86uNGkziudpkNPaCj", accountKeysList.get(5).getPublicKey().toBase58()); + assertEquals("11111111111111111111111111111111", accountKeysList.get(6).getPublicKey().toBase58()); + assertEquals("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", accountKeysList.get(7).getPublicKey().toBase58()); + assertEquals("SysvarRent111111111111111111111111111111111", accountKeysList.get(8).getPublicKey().toBase58()); + assertEquals("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", accountKeysList.get(9).getPublicKey().toBase58()); + } +}