feat(providers): support personal account apis (#2009)
* feat(providers): add personal key mgmt rpcs * add personal_importRawKey and personal_unlockAccount * expose geth personal api * do not prefix with 0x * serialize privkey as string * add allow-insecure-unlock option to Geth
This commit is contained in:
parent
9147ee8e63
commit
c0e607da1e
|
@ -16,7 +16,7 @@ const GETH_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;
|
|||
const GETH_DIAL_LOOP_TIMEOUT: Duration = Duration::new(20, 0);
|
||||
|
||||
/// The exposed APIs
|
||||
const API: &str = "eth,net,web3,txpool,admin,miner";
|
||||
const API: &str = "eth,net,web3,txpool,admin,personal,miner";
|
||||
|
||||
/// The geth command
|
||||
const GETH: &str = "geth";
|
||||
|
@ -180,6 +180,7 @@ pub struct Geth {
|
|||
ipc_path: Option<PathBuf>,
|
||||
data_dir: Option<PathBuf>,
|
||||
chain_id: Option<u64>,
|
||||
insecure_unlock: bool,
|
||||
genesis: Option<Genesis>,
|
||||
mode: GethMode,
|
||||
}
|
||||
|
@ -259,6 +260,13 @@ impl Geth {
|
|||
self
|
||||
}
|
||||
|
||||
/// Allow geth to unlock accounts when rpc apis are open.
|
||||
#[must_use]
|
||||
pub fn insecure_unlock(mut self) -> Self {
|
||||
self.insecure_unlock = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Disable discovery for the geth instance.
|
||||
///
|
||||
/// This will put the geth instance into non-dev mode, discarding any previously set dev-mode
|
||||
|
@ -328,6 +336,11 @@ impl Geth {
|
|||
cmd.arg("--ws.port").arg(port.to_string());
|
||||
cmd.arg("--ws.api").arg(API);
|
||||
|
||||
// pass insecure unlock flag if set
|
||||
if self.insecure_unlock {
|
||||
cmd.arg("--allow-insecure-unlock");
|
||||
}
|
||||
|
||||
// Set the port for authenticated APIs
|
||||
cmd.arg("--authrpc.port").arg(authrpc_port.to_string());
|
||||
|
||||
|
|
|
@ -507,6 +507,25 @@ pub trait Middleware: Sync + Send + Debug {
|
|||
self.inner().mining().await.map_err(FromErr::from)
|
||||
}
|
||||
|
||||
// Personal namespace
|
||||
|
||||
async fn import_raw_key(
|
||||
&self,
|
||||
private_key: Bytes,
|
||||
passphrase: String,
|
||||
) -> Result<Address, ProviderError> {
|
||||
self.inner().import_raw_key(private_key, passphrase).await.map_err(FromErr::from)
|
||||
}
|
||||
|
||||
async fn unlock_account<T: Into<Address> + Send + Sync>(
|
||||
&self,
|
||||
account: T,
|
||||
passphrase: String,
|
||||
duration: Option<u64>,
|
||||
) -> Result<bool, ProviderError> {
|
||||
self.inner().unlock_account(account, passphrase, duration).await.map_err(FromErr::from)
|
||||
}
|
||||
|
||||
// Admin namespace
|
||||
|
||||
async fn add_peer(&self, enode_url: String) -> Result<bool, Self::Error> {
|
||||
|
|
|
@ -818,6 +818,46 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
|
|||
self.request("eth_mining", ()).await
|
||||
}
|
||||
|
||||
// Personal namespace
|
||||
// NOTE: This will eventually need to be enabled by users explicitly because the personal
|
||||
// namespace is being deprecated:
|
||||
// Issue: https://github.com/ethereum/go-ethereum/issues/25948
|
||||
// PR: https://github.com/ethereum/go-ethereum/pull/26390
|
||||
|
||||
/// Sends the given key to the node to be encrypted with the provided passphrase and stored.
|
||||
///
|
||||
/// The key represents a secp256k1 private key and should be 32 bytes.
|
||||
async fn import_raw_key(
|
||||
&self,
|
||||
private_key: Bytes,
|
||||
passphrase: String,
|
||||
) -> Result<Address, ProviderError> {
|
||||
// private key should not be prefixed with 0x - it is also up to the user to pass in a key
|
||||
// of the correct length
|
||||
|
||||
// the private key argument is supposed to be a string
|
||||
let private_key_hex = hex::encode(private_key);
|
||||
let private_key = utils::serialize(&private_key_hex);
|
||||
let passphrase = utils::serialize(&passphrase);
|
||||
self.request("personal_importRawKey", [private_key, passphrase]).await
|
||||
}
|
||||
|
||||
/// Prompts the node to decrypt the given account from its keystore.
|
||||
///
|
||||
/// If the duration provided is `None`, then the account will be unlocked indefinitely.
|
||||
/// Otherwise, the account will be unlocked for the provided number of seconds.
|
||||
async fn unlock_account<T: Into<Address> + Send + Sync>(
|
||||
&self,
|
||||
account: T,
|
||||
passphrase: String,
|
||||
duration: Option<u64>,
|
||||
) -> Result<bool, ProviderError> {
|
||||
let account = utils::serialize(&account.into());
|
||||
let duration = utils::serialize(&duration.unwrap_or(0));
|
||||
let passphrase = utils::serialize(&passphrase);
|
||||
self.request("personal_unlockAccount", [account, passphrase, duration]).await
|
||||
}
|
||||
|
||||
// Admin namespace
|
||||
|
||||
/// Requests adding the given peer, returning a boolean representing whether or not the peer
|
||||
|
|
Loading…
Reference in New Issue