Conversation
joncinque
left a comment
There was a problem hiding this comment.
This is definitely on the right track!
We were talking about this offline, and I mentioned that a good use-case to target is minting SPL tokens, where the mint authority is a multisig, which I think is essentially Trent's sign(sign(sign(... example.
As another consideration, if people want to use tools like Ledgers as their offline signer, I don't think the current format will be accepted. We might need these to look like a Solana transaction instead, so that existing tools Just Work ™️
|
what's status here? foundation wants an example to float to current durable nonce consumers |
|
@t-nelson sorry for the delay on iterating on this. Talked offline to Jon a bit about a simpler design today. Expect an update soon. |
|
inspired by jon This next iteration is an alternative design that simplifies the program a good deal. New flow:
It's no longer necessary to define a custom inner message format. This makes it friendlier to work with existing infra that expects signatures on the legacy transaction format. Also removed embedded deadline/multisig support. Delegates that responsibility to external CPIs. |
t-nelson
left a comment
There was a problem hiding this comment.
making the payload (at least optionally) a transaction i think will ease some migration concerns. we'll need to think about how to handle some of the current features that are specified in transaction payloads, but require runtime support, which will not be available for these. similarly, how the message header will be handled
|
@joncinque @t-nelson re-review on the updated API when you have a chance 🙏 |
| pub nonce: Hash, | ||
| /// Address allowed to consume this nonce and advance its value. `Submit` verifies that this | ||
| /// address signed the wrapped transaction message. | ||
| pub authority: Address, |
There was a problem hiding this comment.
since we're enforcing a 1:1 mapping of authority to pda, this field is superfluous since it must be passed in the tx, right?
There was a problem hiding this comment.
API update here: #1 (comment)
Think parallelism is a legitimate usecase requested from foundation.
There was a problem hiding this comment.
p sure it's the nonce hash that prevents "parallelism", not the authority
we need to tell these people that we're shipping an mvp replacement here, not taking feature requests
There was a problem hiding this comment.
An authority makes sense if we want to cover the existing use-case, where you have a nonce authority that must sign to advance the nonce, and then a bunch of other signers who are signers on the transaction.
A single authority can manage multiple nonce accounts for different offline signers. As a custodian, I might use the same authority for many different clients. When they want to move funds, they sign with one of my many accounts
There was a problem hiding this comment.
sure but we already have the authorities and the submit ix accounts list, as presently defined, only supports a single vault account. we can encode its authority in the ordering, like we do with the fee payer on outer tx, then assert it by virtue of the associated pda being passed. this could be trivially extended to multiple vault accounts should we choose with a vault count in the ix data
There was a problem hiding this comment.
So I'm sure we're on the same page, there's two kinds of accounts: the PDA being promoted, and the account storing the hash and authority. For clarity, let's call the PDA the "vault" since it actually owns assets, and the other account the "durable signer".
In that sense, transactions must have at least one durable signer, and need to support having multiple vaults. Otherwise this program won't support existing use-cases, where multiple keypairs perform offline signing.
| homepage = {workspace = true} | ||
| license = {workspace = true} | ||
| edition = {workspace = true} | ||
| description = "Interface for the SPL Nonce program" |
There was a problem hiding this comment.
i'm thinking maybe we should just drop the "nonce" terminology altogether. any "programmatic signer/authority" can be used to decouple asset authority from signatures that must cover the recent blockhash
There was a problem hiding this comment.
Interesting. Would spl-program-signer or spl-pda-authority or spl-authority-proxy be more accurate?
There was a problem hiding this comment.
spl-ed25519-signer?
@joncinque join the bikeshed session!
There was a problem hiding this comment.
I've been summoned! I really like including ed25519. On the other hand, this is still meant to cover single-use durable signatures, so how about spl-ed25519-durable-signer?
There was a problem hiding this comment.
there really isn't anything "durable" about this thing tho. that qualifier was added to the original feature as a call out to its extending the ttl of an otherwise short-lived nonce value. here we're simply never signing a nonce with a lifetime at all. this is so much more powerful and shouldn't be burdened by historical artifacts. the technology has advanced to the point as to make the old ways irrelevant. let them die
wherever we land, we should also rename the repo before it gets much content
There was a problem hiding this comment.
I'm not sure I understand -- "durable" means "long-lasting", and this program provides a long-lasting way to sign transactions. What are other powers that you want to highlight with the name?
Someone could make a different version of this program that requires signing the same blockhash as the outer transaction, which could be called ed25519-blockhash-signer. In this case, would ed25519-hash-signer be better? Or if you feel really strongly about spl-ed25519-signer, I can get behind it
joncinque
left a comment
There was a problem hiding this comment.
This is on the right path for me, I think implementation can get started very soon!
| pub nonce: Hash, | ||
| /// Address allowed to consume this nonce and advance its value. `Submit` verifies that this | ||
| /// address signed the wrapped transaction message. | ||
| pub authority: Address, |
There was a problem hiding this comment.
An authority makes sense if we want to cover the existing use-case, where you have a nonce authority that must sign to advance the nonce, and then a bunch of other signers who are signers on the transaction.
A single authority can manage multiple nonce accounts for different offline signers. As a custodian, I might use the same authority for many different clients. When they want to move funds, they sign with one of my many accounts
| /// Runs only as an inner instruction of a wrapped transaction submitted through `Submit` | ||
| /// because nothing outside this program can sign for `NonceAuthorityPda`. |
There was a problem hiding this comment.
This is clever! And makes sense, it's a great show of how this would work
There was a problem hiding this comment.
Yeah, I found myself thinking through auth for this message and found the duplication annoying. Think this method addresses that!
| /// 2. Reads the authority stored in the nonce state account. | ||
| /// 3. Checks the passed nonce state account's authority signed the wrapped message. | ||
| /// 4. Checks the wrapped message's lifetime / recent blockhash field equals `state.nonce`. | ||
| /// 5. Verifies the outer transaction's only top-level instruction is `Submit`. |
There was a problem hiding this comment.
I wasn't sure about this restriction, but we can always relax it in the future if there are legitimate use-cases hampered by it
There was a problem hiding this comment.
i think the only real concern is that it makes v1 transactions a prerequisite for consumers that require compute budget instructions
There was a problem hiding this comment.
The program could potentially just skip compute budget instructions, no?
| /// - Remaining: all accounts referenced by the wrapped message, in order, with `is_signer` | ||
| /// and `is_writable` flags matching the wrapped message. |
There was a problem hiding this comment.
We'll see how this shakes out in the implementation, but it isn't possible for non-pda signers to appear in the original message, unless we expect them to sign the inner and outer transactions.
There was a problem hiding this comment.
True. I suppose we could do something where a missing inner signature can be satisfied by outer transaction signer. That sort of would be a way to designate an intended hot wallet broadcaster. Hmm, may be best to come back to this during the implementation PR. Going to drop the is_signer language here for now.
|
This looks good to go from my side to start implementation, but please get @t-nelson 's approval |
This PR adds base interfaces for the program: instructions, state, message schema, and PDA types.
Overall objective
Write a program that can serve as a functional replacement for the durable nonce usecase:
The difference is that durable nonces do this via special runtime functionality (that folks are interested in removing), while this program does it through a promoting a PDA to signer on a pre-signed tx message.
Inspiration
Trent's durable nonce replacement proposal: solana-foundation/solana-improvement-documents#456
& Jon's idea to take a pre-signed-tx and promote the PDA to a signer on that tx.
High-level design
The intended flow is:
a. Verifies the stored authority signed the wrapped message
b. Checks message.lifetime_specifier == state.nonce
c. Executes each wrapped instruction by CPI, promoting DurableSignerPda to signer wherever referenced
d. Advances the nonce as sha256(tag ‖ state_pda ‖ old_nonce ‖ slot_hashes[0] ‖ sha256(message_bytes)).
Divergences from original proposal
This follows the spirit of Trent's original proposal, but there are a few divergences:
What's next