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
//! Command `program`.
use crate::{
    api::Api,
    metadata::Metadata,
    result::{Error, Result},
};
use std::{fs, path::PathBuf};
use structopt::StructOpt;
use subxt::sp_core::H256;

/// Read program state, etc.
#[derive(Clone, Debug, StructOpt)]
pub enum Action {
    /// Read program state.
    State {
        /// Path of "*.meta.wasm".
        metadata: PathBuf,
        /// Input message for reading program state.
        #[structopt(short, long, default_value = "0x")]
        msg: String,
        /// Block timestamp.
        #[structopt(short, long)]
        timestamp: Option<u64>,
        /// Block height.
        #[structopt(short, long)]
        height: Option<u64>,
    },
}

/// Read program state, etc.
#[derive(Debug, StructOpt)]
pub struct Program {
    /// Program id.
    pid: String,
    #[structopt(subcommand)]
    action: Action,
}

impl Program {
    /// Run command program.
    pub async fn exec(&self, api: Api) -> Result<()> {
        let pid_bytes = hex::decode(&self.pid.trim_start_matches("0x"))?;
        let mut pid = [0; 32];
        pid.copy_from_slice(&pid_bytes);

        match self.action {
            Action::State { .. } => self.state(api, pid.into()).await?,
        }

        Ok(())
    }

    /// Read program state.
    pub async fn state(&self, api: Api, pid: H256) -> Result<()> {
        let Action::State {
            metadata,
            msg,
            timestamp,
            height,
        } = self.action.clone();

        // Get program
        let program = api.gprog(pid).await?;
        let code_id = program.code_hash;
        let code = api
            .code_storage(code_id.0)
            .await?
            .ok_or_else(|| Error::CodeNotFound(self.pid.clone()))?;
        let pages = api.gpages(pid, program).await?;

        // Query state
        let state = Metadata::read(
            &fs::read(&metadata)?,
            code.static_pages.0 as u64,
            pages,
            hex::decode(msg.trim_start_matches("0x"))?,
            timestamp.unwrap_or(0),
            height.unwrap_or(0),
        )?;

        println!("state: 0x{}", hex::encode(state));

        Ok(())
    }
}