Skip to content

Commit

Permalink
Merge pull request #79 from zorba128/main
Browse files Browse the repository at this point in the history
Account handling fixed
  • Loading branch information
skynetcap authored Dec 24, 2024
2 parents 0c905af + dee824b commit dc938b7
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 34 deletions.
13 changes: 10 additions & 3 deletions src/main/java/org/p2p/solanaj/core/AccountKeysList.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,33 @@ public class AccountKeysList {
private final Map<String, AccountMeta> accounts;

public AccountKeysList() {
accounts = new HashMap<>();
accounts = new LinkedHashMap<>();
}

public void add(AccountMeta accountMeta) {
String key = accountMeta.getPublicKey().toString();
accounts.merge(key, accountMeta, (existing, newMeta) ->
!existing.isWritable() && newMeta.isWritable() ? newMeta : existing);
new AccountMeta(existing.getPublicKey(),
existing.isSigner() || newMeta.isSigner(),
existing.isWritable() || newMeta.isWritable()));
}

public void addAll(AccountKeysList metas) {
metas.accounts.values().forEach(this::add);
}

public void addAll(Collection<AccountMeta> metas) {
metas.forEach(this::add);
}

/** Retrieve account list sorted by signer/writable attributes. */
public ArrayList<AccountMeta> getList() {
ArrayList<AccountMeta> accountKeysList = new ArrayList<>(accounts.values());
accountKeysList.sort(metaComparator);
return accountKeysList;
}

private static final Comparator<AccountMeta> metaComparator = Comparator
.comparing(AccountMeta::isSigner).reversed()
.comparing(AccountMeta::isSigner)
.thenComparing(AccountMeta::isWritable).reversed();
}
11 changes: 0 additions & 11 deletions src/main/java/org/p2p/solanaj/core/AccountMeta.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,4 @@ public class AccountMeta {

private boolean isWritable;

/**
* Sorting based on isSigner and isWritable cannot fully meet the requirements. This value can be used for custom sorting, because if the order is incorrect during serialization, it may lead to failed method calls.
*/
private int sort = Integer.MAX_VALUE;

public AccountMeta(PublicKey publicKey, boolean isSigner, boolean isWritable) {
this.publicKey = publicKey;
this.isSigner = isSigner;
this.isWritable = isWritable;
}

}
25 changes: 5 additions & 20 deletions src/main/java/org/p2p/solanaj/core/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,26 +147,11 @@ protected void setFeePayer(Account feePayer) {
this.feePayer = feePayer;
}

private List<AccountMeta> getAccountKeys() {
List<AccountMeta> keysList = accountKeys.getList();

// Check whether custom sorting is needed. The `getAccountKeys()` method returns a reversed list of accounts, with signable and mutable accounts at the end, but the fee is placed first. When a transaction involves multiple accounts that need signing, an incorrect order can cause bugs. Change to custom sorting based on the contract order.
boolean needSort = keysList.stream().anyMatch(accountMeta -> accountMeta.getSort() < Integer.MAX_VALUE);
if (needSort) {
// Sort in ascending order based on the `sort` field.
return keysList.stream()
.sorted(Comparator.comparingInt(AccountMeta::getSort))
.collect(Collectors.toList());
}

int feePayerIndex = findAccountIndex(keysList, feePayer.getPublicKey());
List<AccountMeta> newList = new ArrayList<AccountMeta>();
AccountMeta feePayerMeta = keysList.get(feePayerIndex);
newList.add(new AccountMeta(feePayerMeta.getPublicKey(), true, true));
keysList.remove(feePayerIndex);
newList.addAll(keysList);

return newList;
public List<AccountMeta> getAccountKeys() {
AccountKeysList accounts = new AccountKeysList();
accounts.add(new AccountMeta(feePayer.getPublicKey(), true, true));
accounts.addAll(accountKeys);
return accounts.getList();
}

private int findAccountIndex(List<AccountMeta> accountMetaList, PublicKey key) {
Expand Down

0 comments on commit dc938b7

Please sign in to comment.