Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

refactor(experimental): a function to compute program derived addresses #1453

Merged
merged 1 commit into from
Jul 29, 2023

Conversation

steveluscher
Copy link
Contributor

@steveluscher steveluscher commented Jul 28, 2023

refactor(experimental): a function to compute program derived addresses

Summary

Given a program address and a series of string or bytearray seeds, this function will compute the off-chain program derived address (PDA) corresponding to both.

Test Plan

cd packages/addresses
pnpm test:unit:browser
pnpm test:unit:node

Implements #1446.

@@ -0,0 +1,20 @@
Copyright (c) 2018 Solana Labs, Inc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IANAL.

Comment on lines 54 to 56
### `getBase58EncodedAddressFromPublicKey()`

Given a public `CryptoKey`, this method will return its associated `Base58EncodedAddress`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how this will feel in practice but in theory i like the distinction between pubkeys and addresses

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if the method name could be shorter tho, since it will be used a lot. getAddressFromPublicKey? or maybe have a toAddress() on the CryptoKey?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm into it. If we can agree that the commonly used thing (the base58 string) is what we mean when we say ‘address’ then we can rename all the methods for the common case, and reserve the more wordy function names for the more uncommon cases (getAddressBytesFromFoo() etc).

I'll still keep the TypeScript types the way they are though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not necessary for this pr but when in "finishing touches" mode this is the kind of thing i personally would have a set of tests like "generate a few thousand random base addresses and seed strings and assert the old and new libraries produce the same result"

]);
expect(pdaButterfly).toStrictEqual(pdaButterFly);
});
// https://solana.stackexchange.com/questions/7253/what-combination-of-program-address-and-seeds-would-cause-findprogramaddress-t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hahaha i love the completionism

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noting for posterity that obvi i cant review this but clearly its third party code anyway

Copy link
Contributor Author

@steveluscher steveluscher Jul 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oic you're not familiar with my stacked PR workflow and you probably reviewed every commit in here. Each PR in this stack is only ‘about’ the top commit. The other commits before the last one are just there, because GitHub.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other words, wow thanks for reviewing the whole stack! :)

@2501babe
Copy link
Contributor

thank you for your service, ill try using this soon

@2501babe
Copy link
Contributor

2501babe commented Jul 28, 2023

incidentally are we going back to not having a synchronous version of this... i know its probably something like "blah blah web workers 0.0001s speedup" but its just convenient not having pda generation infect the entire codebase with async/await, because its used so much in simple utility functions very far away on the code graph from real network calls

Copy link
Contributor

@mcintyre94 mcintyre94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

programAddress: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' as Base58EncodedAddress,
seeds: [
// Owner
serialize('9fYLFVoVqwH37C3dyPi6cpeobfbQ2jtLpN5HgAYDDdkm' as Base58EncodedAddress),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this return the same bytes as new PublicKey('9fYLFVoVqwH37C3dyPi6cpeobfbQ2jtLpN5HgAYDDdkm').toBuffer() in the old lib?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does!

> new PublicKey('9fYLFVoVqwH37C3dyPi6cpeobfbQ2jtLpN5HgAYDDdkm').toBuffer()
<Buffer 80 bc fe 45 2a 9a 00 99 12 7e 5e de 0f 4f 69 98 01 18 0f a0 75 af c9 f5 df 28 ec 9b 28 c0 5d ba>
> Buffer.from(getBase58EncodedAddressCodec().serialize('9fYLFVoVqwH37C3dyPi6cpeobfbQ2jtLpN5HgAYDDdkm'))
<Buffer 80 bc fe 45 2a 9a 00 99 12 7e 5e de 0f 4f 69 98 01 18 0f a0 75 af c9 f5 df 28 ec 9b 28 c0 5d ba>

bumpSeed: 251,
pda: '46v3JvPtEPeQmH3euXydEbxYD6yfxeZjWSzkkYvvM5Pp',
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of interest did you use some trick to generate these examples? Mainly asking because they all have bumpSeed 251

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generating a few addresses for the tests until exactly that is the case.

programAddress: Base58EncodedAddress;
seeds: Seed[];
}>;
type Seed = string | Uint8Array;
Copy link
Contributor

@mcintyre94 mcintyre94 Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not suggesting we should keep the existing interface, but do you know how you'd convert from a Buffer in the old code to this?

I remember that when I used Buffer.from([posX, posY]) (posX and posY are 0-255, u8 in rust) as a seed, I couldn't switch it to a Uint8Array and get the same result in the old code

I'm not sure if the different implementation here means that new Uint8Array([posX, posY]) would be equivalent?

Copy link
Contributor Author

@steveluscher steveluscher Jul 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It definitely is.

> Buffer.from([64, 216])
<Buffer 40 d8>
> new Uint8Array([64, 216])
Uint8Array(2) [ 64, 216 ]
> 0x40 === 64
true
> 0xd8 === 216
true

Buffer has always been a pain in the ass because it's a Node-only primitive that has required a polyfill in browser, for almost no gain: #1100

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember that when I used Buffer.from([posX, posY]) (posX and posY are 0-255, u8 in rust) as a seed, I couldn't switch it to a Uint8Array and get the same result in the old code

Very sus! We should try to repro that and figure out why.

@steveluscher steveluscher force-pushed the pr1453 branch 3 times, most recently from fc9ccd0 to 6afc39b Compare July 29, 2023 00:00
@steveluscher
Copy link
Contributor Author

steveluscher commented Jul 29, 2023

are we going back to not having a synchronous version of this...

  1. I'm pretty sure that if I did enough digging through GitHub issues I'd find a bunch of folks who were really mad about the move to sync versions of our key manipulation functions because their apps were key-heavy and sync versions kneecapped their performance severely.
  2. We absolutely have no choice. Native Ed25519 primitives are coming to every JavaScript engine, and every single bit of those APIs is async.

cc/ @2501babe

@steveluscher steveluscher force-pushed the pr1453 branch 2 times, most recently from ec013a2 to 45abc41 Compare July 29, 2023 00:27
# Summary

Given a program address and a series of string or bytearray seeds, this function will compute the off-chain program derived address (PDA) corresponding to both.

# Test Plan

```
cd packages/addresses
pnpm test:unit:browser
pnpm test:unit:node
```
@github-actions
Copy link
Contributor

🎉 This PR is included in version 1.78.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions
Copy link
Contributor

Because there has been no activity on this PR for 14 days since it was merged, it has been automatically locked. Please open a new issue if it requires a follow up.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants