loom_broadcast_accounts/signers/
initialize_actor.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use alloy_primitives::{hex, Bytes, B256};
use eyre::eyre;
use tracing::{error, info};

use loom_core_actors::{Accessor, Actor, ActorResult, SharedState, WorkerResult};
use loom_core_actors_macros::Accessor;
use loom_core_blockchain::Blockchain;
use loom_types_entities::{AccountNonceAndBalanceState, KeyStore, TxSigners};
use revm::DatabaseRef;

/// The one-shot actor adds a new signer to the signers and monitor list after and stops.
#[derive(Accessor)]
pub struct InitializeSignersOneShotBlockingActor {
    key: Option<Vec<u8>>,
    #[accessor]
    signers: Option<SharedState<TxSigners>>,
    #[accessor]
    monitor: Option<SharedState<AccountNonceAndBalanceState>>,
}

async fn initialize_signers_one_shot_worker(
    key: Vec<u8>,
    signers: SharedState<TxSigners>,
    monitor: SharedState<AccountNonceAndBalanceState>,
) -> WorkerResult {
    let new_signer = signers.write().await.add_privkey(Bytes::from(key));
    monitor.write().await.add_account(new_signer.address());
    info!("New signer added {:?}", new_signer.address());
    Ok("Signer added".to_string())
}

impl InitializeSignersOneShotBlockingActor {
    pub fn new(key: Option<Vec<u8>>) -> InitializeSignersOneShotBlockingActor {
        let key = key.unwrap_or_else(|| B256::random().to_vec());

        InitializeSignersOneShotBlockingActor { key: Some(key), signers: None, monitor: None }
    }

    pub fn new_from_encrypted_env() -> InitializeSignersOneShotBlockingActor {
        let key = match std::env::var("DATA") {
            Ok(priv_key_enc) => {
                let keystore = KeyStore::new();
                let key = keystore.encrypt_once(hex::decode(priv_key_enc).unwrap().as_slice()).unwrap();
                Some(key)
            }
            _ => None,
        };

        InitializeSignersOneShotBlockingActor { key, signers: None, monitor: None }
    }

    pub fn new_from_encrypted_key(priv_key_enc: Vec<u8>) -> InitializeSignersOneShotBlockingActor {
        let keystore = KeyStore::new();
        let key = keystore.encrypt_once(priv_key_enc.as_slice()).unwrap();

        InitializeSignersOneShotBlockingActor { key: Some(key), signers: None, monitor: None }
    }

    pub fn on_bc<DB: DatabaseRef + Send + Sync + Clone + 'static>(self, bc: &Blockchain<DB>) -> Self {
        Self { monitor: Some(bc.nonce_and_balance()), ..self }
    }

    pub fn with_signers(self, signers: SharedState<TxSigners>) -> Self {
        Self { signers: Some(signers), ..self }
    }
}

impl Actor for InitializeSignersOneShotBlockingActor {
    fn start_and_wait(&self) -> eyre::Result<()> {
        let key = match self.key.clone() {
            Some(key) => key,
            _ => {
                error!("No signer keys found");
                return Err(eyre!("NO_SIGNER_KEY"));
            }
        };
        let (signers, monitor) = match (self.signers.clone(), self.monitor.clone()) {
            (Some(signers), Some(monitor)) => (signers, monitor),
            _ => {
                error!("Signers or monitor not initialized");
                return Err(eyre!("SIGNERS_OR_MONITOR_NOT_INITIALIZED"));
            }
        };

        let rt = tokio::runtime::Runtime::new()?; // we need a different runtime to wait for the result
        let handle = rt.spawn(async { initialize_signers_one_shot_worker(key, signers, monitor).await });

        self.wait(Ok(vec![handle]))?;
        rt.shutdown_background();

        Ok(())
    }
    fn start(&self) -> ActorResult {
        Err(eyre!("NEED_TO_BE_WAITED"))
    }

    fn name(&self) -> &'static str {
        "InitializeSignersOneShotBlockingActor"
    }
}