Skip to content

Commit

Permalink
fix: account keys order
Browse files Browse the repository at this point in the history
  • Loading branch information
b1acksun committed Aug 19, 2021
1 parent 1125e61 commit f83f95b
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 34 deletions.
45 changes: 24 additions & 21 deletions src/main/java/org/p2p/solanaj/core/AccountKeysList.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, AccountMeta> accounts;
private List<AccountMeta> accountsList;

public AccountKeysList() {
accounts = new HashMap<String, AccountMeta>();
accountsList = new ArrayList<AccountMeta>();
}

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<AccountMeta> metas) {
for (AccountMeta meta : metas) {
add(meta);
}
accountsList.addAll(metas);
}

public ArrayList<AccountMeta> getList() {
ArrayList<AccountMeta> accountKeysList = new ArrayList<AccountMeta>(accounts.values());
accountKeysList.sort(metaComparator);
public List<AccountMeta> getList() {
ArrayList<AccountMeta> uniqueMetas = new ArrayList<AccountMeta>();

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<AccountMeta> metaComparator = new Comparator<AccountMeta>() {
Expand All @@ -53,7 +56,7 @@ public int compare(AccountMeta am1, AccountMeta am2) {
return cmpkWritable;
}

return Integer.compare(cmpSigner, cmpkWritable);
return 0;
}
};

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/p2p/solanaj/core/AccountMeta.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.p2p.solanaj.core;

import java.util.List;

public class AccountMeta {
private PublicKey publicKey;
private boolean isSigner;
Expand All @@ -22,4 +24,14 @@ public boolean isSigner() {
public boolean isWritable() {
return isWritable;
}

public static int findAccountIndex(List<AccountMeta> accountMetaList, PublicKey key) {
for (int i = 0; i < accountMetaList.size(); i++) {
if (accountMetaList.get(i).getPublicKey().equals(key)) {
return i;
}
}

return -1;
}
}
27 changes: 14 additions & 13 deletions src/main/java/org/p2p/solanaj/core/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,22 @@ int getLength() {
private AccountKeysList accountKeys;
private List<TransactionInstruction> instructions;
private PublicKey feePayer;
private List<String> programIds;

public Message() {
this.programIds = new ArrayList<String>();
this.accountKeys = new AccountKeysList();
this.instructions = new ArrayList<TransactionInstruction>();
}

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;
}

Expand All @@ -71,6 +76,9 @@ public byte[] serialize() {

messageHeader = new MessageHeader();

for (String programId : programIds) {
accountKeys.add(new AccountMeta(new PublicKey(programId), false, false));
}
List<AccountMeta> keysList = getAccountKeys();
int accountKeysSize = keysList.size();

Expand All @@ -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);
Expand Down Expand Up @@ -148,7 +158,7 @@ protected void setFeePayer(PublicKey feePayer) {

private List<AccountMeta> getAccountKeys() {
List<AccountMeta> keysList = accountKeys.getList();
int feePayerIndex = findAccountIndex(keysList, feePayer);
int feePayerIndex = AccountMeta.findAccountIndex(keysList, feePayer);

List<AccountMeta> newList = new ArrayList<AccountMeta>();

Expand All @@ -164,13 +174,4 @@ private List<AccountMeta> getAccountKeys() {
return newList;
}

private int findAccountIndex(List<AccountMeta> accountMetaList, PublicKey key) {
for (int i = 0; i < accountMetaList.size(); i++) {
if (accountMetaList.get(i).getPublicKey().equals(key)) {
return i;
}
}

return -1;
}
}
49 changes: 49 additions & 0 deletions src/test/java/org/p2p/solanaj/core/AccountKeysListTest.java
Original file line number Diff line number Diff line change
@@ -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<AccountMeta> 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());
}
}

0 comments on commit f83f95b

Please sign in to comment.