Skip to content

Commit

Permalink
feat: add update wallet to CLI WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
driemworks committed Nov 5, 2024
1 parent 43784ab commit f6b0dc6
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 126 deletions.
34 changes: 0 additions & 34 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,26 @@ workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
[dependencies]
totp-rs = { version = "5.5.1", default-features = false, optional = true }
codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"], default-features = false }
etf-crypto-primitives = { git = "https://github.com/ideal-lab5/etf-sdk/", branch = "dev", default-features = false }
ckb-merkle-mountain-range = { version = "0.5.2", default-features = false }
sha3 = { version = "0.10.8", default-features = false }
serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false}
serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false }
ark-bls12-377 = { version = "0.4.0", default-features = false }
ark-std = { version = "0.4.0", default-features = false }
ark-serialize = { version = "0.4.0", default-features = false }
w3f-bls = { version = "0.1.3", default-features = false }
zeroize = { version = "1.8.1", default-features = false }
rand_chacha = { version = "0.3.1" }
hkdf = "0.12.4"
ark-ec = { version = "0.4", default-features = false }
ark-ff = { version = "0.4", default-features = false }
dleq_vrf = { git = "https://github.com/w3f/ring-vrf.git", default-features = false }
ark-transcript = { git = "https://github.com/w3f/ring-vrf.git", default-features = false }

[dev-dependencies]
rand_core = { version = "0.6.4", features = ["getrandom"], default-features = false }
hkdf = "0.12.4"
rand_chacha = { version = "0.3.1" }
rand_core = { version = "0.6.4" }

[features]
default = ["client"]
Expand Down
214 changes: 143 additions & 71 deletions lib/src/bin/murmur/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,44 @@ struct Cli {
commands: Commands,
}

/// Commands available to user
#[derive(Subcommand)]
enum Commands {
/// create a new murmur wallet
/// create a new Murmur wallet
New(WalletCreationDetails),
/// dispatch (proxy) a call to a murmur wallet
/// Update an existing Murmur wallet
Update(WalletCreationDetails),
/// dispatch (proxy) a call to a Murmur wallet
Execute(WalletExecuteDetails),
}

/// Arguments for creation and updating a wallet
#[derive(Parser)]
struct WalletCreationDetails {
/// The name of the wallet
#[arg(long, short)]
name: String,
/// The seed of the wallet (i.e. password)
#[arg(long, short)]
seed: String,
/// The lifetime (from now) of the wallet in blocks
#[clap(long, short)]
validity: u32,
}

/// Arguments for executing a balance transfer from the wallet
#[derive(Parser)]
struct WalletExecuteDetails {
/// The name of the wallet
#[arg(long, short)]
name: String,
/// The seed of the wallet (i.e. password)
#[arg(long, short)]
seed: String,
/// The recipient (ss58 encoded)
#[arg(long, short)]
to: String,
/// The amount to send TODO formatting
#[arg(short, long, value_parser = clap::value_parser!(u128))]
amount: u128,
}
Expand Down Expand Up @@ -94,82 +106,142 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

match &cli.commands {
Commands::New(args) => {
println!("🏭 Murmur: Generating Merkle mountain range");

// 1. prepare block schedule
let mut schedule: Vec<BlockNumber> = Vec::new();
for i in 2..args.validity + 2 {
// wallet is 'active' in 2 blocks
let next_block_number: BlockNumber = current_block_number + i;
schedule.push(next_block_number);
}

// 2. create mmr
let mmr_store =
create(args.seed.as_bytes().to_vec(), 0, schedule, round_pubkey_bytes, &mut rng)
.map_err(|_| CLIError::MurmurCreationFailed)?;

// 3. add to storage
write_mmr_store(mmr_store.clone(), MMR_STORE_FILEPATH);

// 4. build the call
let call = etf::tx().murmur().create(
mmr_store.root.0,
mmr_store.metadata.keys().len() as u64,
BoundedVec(args.name.as_bytes().to_vec()),
);

// 5. sign and send the call
client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?;

println!("✅ MMR proxy account creation successful!");
handle_create(args, client, current_block_number, round_pubkey_bytes, rng).await?
},
Commands::Execute(args) => {
// 1. build proxied call
let from_ss58 = sp_core::crypto::AccountId32::from_ss58check(&args.to)
.map_err(|_| CLIError::InvalidRecipient)?;
let bytes: &[u8] = from_ss58.as_ref();
let from_ss58_sized: [u8; 32] =
bytes.try_into().map_err(|_| CLIError::InvalidRecipient)?;
let to = subxt::utils::AccountId32::from(from_ss58_sized);
let balance_transfer_call =
RuntimeCall::Balances(etf::balances::Call::transfer_allow_death {
dest: subxt::utils::MultiAddress::<_, u32>::from(to),
value: args.amount,
});

// 2. load the MMR store
let store: MurmurStore = load_mmr_store(MMR_STORE_FILEPATH)?;
println!("💾 Recovered Murmur store from local file");

// 3. get the proxy data
let proxy_data = prepare_execute(
args.seed.as_bytes().to_vec(),
current_block_number + 1,
store,
&balance_transfer_call,
&mut rng,
)
.map_err(|_| CLIError::MurmurExecutionFailed)?;

// 4. build the call
let call = etf::tx().murmur().proxy(
BoundedVec(args.name.as_bytes().to_vec()),
proxy_data.position,
proxy_data.hash,
proxy_data.ciphertext,
proxy_data.proof_items,
proxy_data.size,
balance_transfer_call,
);
// 5. sign and send the call
client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?;
Commands::Update(args) => {
// handle_update(args, client, current_block_number, round_pubkey_bytes, rng).await?
},
Commands::Execute(args) => handle_execute(args, client, current_block_number, rng).await?,
}

println!("Elapsed time: {:.2?}", before.elapsed());
Ok(())
}

/// This function creates a new Murmur wallet
async fn handle_create(
args: &WalletCreationDetails,
client: OnlineClient<SubstrateConfig>,
current_block_number: BlockNumber,
round_pubkey_bytes: Vec<u8>,
mut rng: ChaCha20Rng,
) -> Result<(), Box<dyn std::error::Error>> {
let mmr_store = build_mmr_store(args, current_block_number, round_pubkey_bytes, rng)?;
let call = etf::tx().murmur().create(
BoundedVec(args.name.as_bytes().to_vec()),
mmr_store.root.0,
mmr_store.metadata.keys().len() as u64,
mmr_store.proof,
mmr_store.public_key,
);

client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?;

println!("✅ Murmur Proxy Creation: Successful!");

Ok(())
}

// /// This function updates an existing Murmur wallet
// async fn handle_update(
// args: &WalletCreationDetails,
// client: OnlineClient<SubstrateConfig>,
// current_block_number: BlockNumber,
// round_pubkey_bytes: Vec<u8>,
// mut rng: ChaCha20Rng,
// ) -> Result<(), Box<dyn std::error::Error>> {
// let mmr_store = build_mmr_store(args, current_block_number, round_pubkey_bytes, &mut rng)?;

// let call = etf::tx().murmur().update(
// BoundedVec(args.name.as_bytes().to_vec()),
// mmr_store.root.0,
// mmr_store.metadata.keys().len() as u64,
// mmr_store.proof,
// );

// client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?;

// println!("✅ Murmur Proxy Update: Successful!");

// Ok(())
// }

/// Build a new Murmur store for each block from `current_block_number + 2` to `current_block_number + args.validity`
fn build_mmr_store(
args: &WalletCreationDetails,
current_block_number: BlockNumber,
round_pubkey_bytes: Vec<u8>,
mut rng: ChaCha20Rng,
) -> Result<MurmurStore, Box<dyn std::error::Error>> {
println!("🏗️ Murmur: Generating Merkle mountain range");
// 1. prepare block schedule
let mut schedule: Vec<BlockNumber> = Vec::new();
for i in 2..args.validity + 2 {
// wallet is 'active' in 2 blocks
let next_block_number: BlockNumber = current_block_number + i;
schedule.push(next_block_number);
}

// 2. create mmr
let mmr_store =
create(args.seed.as_bytes().to_vec(), 0, schedule, round_pubkey_bytes, &mut rng)
.map_err(|_| CLIError::MurmurCreationFailed)?;

// 3. add to storage
write_mmr_store(mmr_store.clone(), MMR_STORE_FILEPATH);

Ok(mmr_store)
}

/// This function executes a call from the Murmur proxy at block after the provided `current_block_height`
/// note that this does not guarantee execution. If the transaction is not included in a block in the upcoming block
/// then it will never be executed
async fn handle_execute(
args: &WalletExecuteDetails,
client: OnlineClient<SubstrateConfig>,
current_block_number: BlockNumber,
mut rng: ChaCha20Rng,
) -> Result<(), Box<dyn std::error::Error>> {
// 1. build proxied call
let from_ss58 = sp_core::crypto::AccountId32::from_ss58check(&args.to)
.map_err(|_| CLIError::InvalidRecipient)?;
let bytes: &[u8] = from_ss58.as_ref();
let from_ss58_sized: [u8; 32] = bytes.try_into().map_err(|_| CLIError::InvalidRecipient)?;
let to = subxt::utils::AccountId32::from(from_ss58_sized);
let balance_transfer_call = RuntimeCall::Balances(etf::balances::Call::transfer_allow_death {
dest: subxt::utils::MultiAddress::<_, u32>::from(to),
value: args.amount,
});

// 2. load the MMR store
let store: MurmurStore = load_mmr_store(MMR_STORE_FILEPATH)?;
println!("💾 Recovered Murmur store from local file");

// 3. get the proxy data
let proxy_data = prepare_execute(
args.seed.as_bytes().to_vec(),
current_block_number + 1,
store,
&balance_transfer_call,
&mut rng,
)
.map_err(|_| CLIError::MurmurExecutionFailed)?;

// 4. build the call
let call = etf::tx().murmur().proxy(
BoundedVec(args.name.as_bytes().to_vec()),
proxy_data.position,
proxy_data.hash,
proxy_data.ciphertext,
proxy_data.proof_items,
proxy_data.size,
balance_transfer_call,
);
// 5. sign and send the call
client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?;
Ok(())
}

/// Async connection to the Ideal Network
/// if successful then fetch data
/// else error if unreachable
Expand Down
15 changes: 0 additions & 15 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,6 @@ impl IdentityBuilder<BlockNumber> for BasicIdBuilder {
}
}

#[derive(Serialize)]
/// Data needed to build a valid call for creating a murmur wallet.
pub struct CreateData {
/// The root of the MMR
pub root: Vec<u8>,
/// The size of the MMR
pub size: u64,
/// The murmur store (map of block nubmer to ciphertext)
pub mmr_store: MurmurStore,
/// The serialized VRF public key
pub public_key_bytes: Vec<u8>,
/// The serialized Schnorr signature
pub proof_bytes: Vec<u8>,
}

#[derive(Serialize)]
/// Data needed to build a valid call for a proxied execution.
pub struct ProxyData {
Expand Down

0 comments on commit f6b0dc6

Please sign in to comment.