-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: signers #44
feat: signers #44
Conversation
huge |
crates/signer-ledger/src/app.rs
Outdated
} | ||
TypedTransaction::Legacy(_) => eip155_chain_id + ecc_parity, | ||
#[cfg(feature = "optimism")] | ||
TypedTransaction::DepositTransaction(_) => 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deposit transactions never contain signatures since they are side effects of events emitted from L1. It should never hit this branch so perhaps should panic
or error if a user tries to sign a DepositTransaction
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- ported 1-1 from ethers
- we don't even have this type so
sign_transaction
-related code is configured out for now - this code in specific was removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing in this workspace should have optimism support yet either. please remove
@@ -42,7 +42,7 @@ When updating this, also update: | |||
|
|||
Alloy will keep a rolling MSRV (minimum supported rust version) policy of **at | |||
least** 6 months. When increasing the MSRV, the new Rust version must have been | |||
released at least six months ago. The current MSRV is 1.65.0. | |||
released at least six months ago. The current MSRV is 1.68. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aws-sdk-kms 1.68, with msrv at 1.70 in readme. I think we'll want to bump this to latest stable for AFIT anyway
d0d8c40
to
49961f2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing major. straightforward port. I think the arch questions outstanding are
- what do we do about txns?
- Wallet
- does Wallet provide anything meaningful besides address caching?
- should the ledger/trezor/aws signers use the Wallet scaffold?
- should wallet be a separate crate?
- Can we smoothly provide signers/wallets with access to multiple addresses by revisiting the API design?
- e.g. all of ledger/trezor/aws/mnemonic may have a key inventory instead of just a key
crates/signer/src/signer.rs
Outdated
/// [EIP-712]: https://eips.ethereum.org/EIPS/eip-712 | ||
#[cfg(feature = "eip712")] | ||
#[inline] | ||
fn sign_typed_data<T: SolStruct + Send + Sync>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should Send
and Sync
and 'static
be supertraits of SolStruct
? is there any situation in which we allow/want SolStructs
to have anything other than dumb data in them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I generally dislike slapping "send sync static" combo everywhere
crates/signer/src/wallet/mod.rs
Outdated
@@ -0,0 +1,87 @@ | |||
use crate::{Result, Signature, Signer}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should wallet be a separate crate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this, but I don't believe it makes much sense since it uses the same dependencies
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, i don't love that Wallet
is special wrt other implementors of Signer
🤔 should all of them be Wallet<T>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't understand this question, wallet is generic over the underlying private key type basically
|
||
/// Creates a new random keypair seeded with the provided RNG. | ||
#[inline] | ||
pub fn random_with<R: Rng + CryptoRng>(rng: &mut R) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can these be feature-gated? Generally we don't want people to be doing this 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? Rand is brought in from deps anyway, and it's nice in tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a random raw key is essentially never best practice, and shouldn't be in the standard API. We want to recommend users not use this API and feature gating it is a good way to do that
/// The inner ECDSA signature. | ||
inner: ecdsa::Signature, | ||
/// The recovery ID. | ||
recid: RecoveryId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a good resource where i can read about the recovery ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is amazing, thanks. Is there any plan to have a more basic version of signing in the core crates so we can have no_std support please? |
/// Synchronous signers should implement both this trait and [`SignerSync`]. | ||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] | ||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] | ||
pub trait Signer: Send + Sync { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally object safe Signers
/// Synchronous signers should implement both this trait and [`SignerSync`]. | ||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] | ||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] | ||
pub trait Signer: Send + Sync { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to impl this for Box
as well?
but can do seprately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can do &mut
and Box
on Signer only due to set_chain_id
: e06356a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't go through every part of the impls, but signer trait design looks good, and I like that we're using the new AWS sdk. Let's track adding https://github.com/georgewhewell/ethers-gcp-kms-signer upstream in an issue?
If there's no other blocker, let's do the typed tx derive, and get this in! And I think then we need:
- a signer-aware provider, with some path for general middlewares ( we should discuss design in person)
- wiring of the provider/middleware with
sol!
and with dyn-abi - ..? done?
/// Signs the transaction. | ||
#[cfg(TODO)] // TODO: TypedTransaction | ||
#[inline] | ||
async fn sign_transaction(&self, message: &TypedTransaction) -> Result<Signature> { | ||
self.sign_hash(&message.sighash()).await | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirming we need to derive RLP here, and that's the main blocker? https://github.com/alloy-rs/alloy/blob/main/crates/rpc-types/src/eth/transaction/typed.rs#L18
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, a transaction request is not a transaction. transaction requests may contain incomplete data, and are never RLP serialized
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also strongly advise keeping that separate and not adding any rlp support to Request
types (Optional fields).
having dealt with that RPC Request -> Transaction -> Receipt
mess a few times now, that's the only way to keep it manageable, even if slightly less convenient than having rlp support on Receipt
and Request
types directly.
I think the solution we're looking for is:
- builder style
Request
types (Optional fields) that have a correspondingTransaction
type (valid Transaction). going fromRequest -> Transaction
is what we calledfill
in ethers. we only really need this forsign_tx
/send_rawTransaction
.
Then there are also receipt types (RPC responses) for which we should add helpers to
a) convert to Request
b) fallible conversion into Transaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
builder style Request types (Optional fields) that have a corresponding Transaction type (valid Transaction).
yes, love this plan :)
going from Request -> Transaction is what we called fill in ethers.
This is a little more complex, I think. The TransactionRequest
generally allows a from
field, which the Transaction
that implements RLP should not
So we may want something like:
Transaction
- complete, no from field, implements RLP, no serdeSignedTransaction
- complete, no from field, contains Transaction + Signature, no serde- TransactionRequest - builder for the JSON request object
Provider::fill(&mut TransactionRequest)
- populates all possible fields from RPC node
- should ensure that
TransactionRequest::try_into_transaction
definitely succeeds
Signer::sign_transaction(&TransactionRequest) -> Result<SignedTransaction>
- errors when the request is missing info, or if
from
is populated with address signer can't sign from
- errors when the request is missing info, or if
TransactionResponse
- JSON object returned byeth_getTransactionByXXXX
methods- should ALWAYS contain a
SignedTransaction
- should ALWAYS contain a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. Supportive of this. Let's do in follow-up @DaniPopes so we can merge this in?
We also want a Transaction
(the. one you get via the mempool subscription, or eth_getTransactionByXX
) -> TransactionRequest
helper, right?
Also, doesn't TransactionRequest::try_into_transaction
require signing the request first? So maybe it's actually SignedTransaction::into_transaction
?
Motivation
Add
signer[-*]
crates.Solution
PR Checklist