Skip to content

Account delete #3

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

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions src/cli/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ pub enum AccountCmd {
#[clap(short, long, default_value_t = false)]
deploy: bool,
},

/// Remove existing account from the local store
#[clap(short_flag = 'r')]
Remove {
#[clap()]
id: String,
},
}

#[derive(Debug, Parser, Clone)]
Expand Down Expand Up @@ -64,6 +71,7 @@ impl AccountCmd {
new_account(template, *deploy)?;
}
AccountCmd::View { id: _ } => todo!(),
AccountCmd::Remove { id } => remove_account(id)?,
}
Ok(())
}
Expand Down Expand Up @@ -153,10 +161,10 @@ fn new_account(template: &Option<AccountTemplate>, deploy: bool) -> Result<(), S
// TODO: Make these inserts atomic through a single transaction
client
.store()
.insert_account(&account)
.and_then(|_| client.store().insert_account_code(account.code()))
.insert_account_code(account.code())
.and_then(|_| client.store().insert_account_storage(account.storage()))
.and_then(|_| client.store().insert_account_vault(account.vault()))
.and_then(|_| client.store().insert_account(&account))
.map(|_| {
println!(
"Succesfully created and stored Account ID: {}",
Expand All @@ -167,3 +175,20 @@ fn new_account(template: &Option<AccountTemplate>, deploy: bool) -> Result<(), S

Ok(())
}

// ACCOUNT REMOVE
// ================================================================================================

fn remove_account(id: &str) -> Result<(), String> {
let mut client = Client::new(ClientConfig::default()).map_err(|err| err.to_string())?;

let without_prefix = id.trim_start_matches("0x");
let account_id: u64 = u64::from_str_radix(without_prefix, 16).map_err(|err| err.to_string())?;
client
.store_mut()
.remove_account(account_id)
.map_err(|err| err.to_string())?;

println!("Succesfully removed Account ID: {}", id);
Ok(())
}
2 changes: 2 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum StoreError {
QueryError(rusqlite::Error),
InputSerializationError(serde_json::Error),
DataDeserializationError(serde_json::Error),
NotFound,
}

impl fmt::Display for StoreError {
Expand All @@ -53,6 +54,7 @@ impl fmt::Display for StoreError {
DataDeserializationError(err) => {
write!(f, "error deserializing data from the store: {err}")
}
NotFound => write!(f, "requested data was not found in the store"),
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ impl Client {
&self.store
}

/// Returns a mutable reference to the store
pub fn store_mut(&mut self) -> &mut Store {
&mut self.store
}

// DATA RETRIEVAL
// --------------------------------------------------------------------------------------------

Expand Down
75 changes: 74 additions & 1 deletion src/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,85 @@ impl Store {

self.db
.execute(
"INSERT INTO account_vault (root, assets) VALUES (?, ?)",
"INSERT INTO account_vaults (root, assets) VALUES (?, ?)",
params![vault_root, assets],
)
.map(|_| ())
.map_err(StoreError::QueryError)
}

pub fn remove_account(&mut self, account_id: u64) -> Result<(), StoreError> {
let tx = self.db.transaction().map_err(StoreError::ConnectionError)?;

let Ok((code_root, storage_root, vault_root)) = tx.query_row(
"SELECT code_root, storage_root, vault_root FROM accounts WHERE id = ? ",
params![account_id as i64],
|row| {
let code_root: String = row.get(0)?;
let storage_root: String = row.get(1)?;
let vault_root: String = row.get(2)?;

Ok((code_root, storage_root, vault_root))
},
) else {
return Err(StoreError::NotFound);
};

// Remove from accounts table
if tx
.execute(
"DELETE FROM accounts WHERE id = ?",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's simple enough, it would be nice to see a test that tests this function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, to do this we should merge this branch with cli testing

params![account_id as i64],
)
.map_err(StoreError::QueryError)?
== 0
{
return Err(StoreError::NotFound);
}

// Remove from account_keys table
// Currently not stored

// Remove from account_code table
// should only be removed if it is not used by any other account
if tx
.execute(
"DELETE FROM account_code WHERE root = ?",
params![code_root],
)
.map_err(StoreError::QueryError)?
== 0
{
return Err(StoreError::NotFound);
}

// Remove from account_storage table
if tx
.execute(
"DELETE FROM account_storage WHERE root = ?",
params![storage_root],
)
.map_err(StoreError::QueryError)?
== 0
{
return Err(StoreError::NotFound);
}

// Remove from account_vaults table
if tx
.execute(
"DELETE FROM account_vaults WHERE root = ?",
params![vault_root],
)
.map_err(StoreError::QueryError)?
== 0
{
return Err(StoreError::NotFound);
}

tx.commit().map_err(StoreError::ConnectionError)?;
Ok(())
}
}

// STORE CONFIG
Expand Down
45 changes: 30 additions & 15 deletions src/store/store.sql
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
-- Create account_code table
CREATE TABLE account_code (
root BLOB NOT NULL, -- root of the Merkle tree for all exported procedures in account module.
procedures BLOB NOT NULL, -- serialized procedure digests for the account code.
module BLOB NOT NULL -- serialized ModuleAst for the account code.
root BLOB NOT NULL, -- root of the Merkle tree for all exported procedures in account module.
procedures BLOB NOT NULL, -- serialized procedure digests for the account code.
module BLOB NOT NULL, -- serialized ModuleAst for the account code.
PRIMARY KEY (root)
);

-- Create account_storage table
CREATE TABLE account_storage (
root BLOB NOT NULL, -- root of the account storage Merkle tree.
slots BLOB NOT NULL -- serialized key-value pair of non-empty account slots.
root BLOB NOT NULL, -- root of the account storage Merkle tree.
slots BLOB NOT NULL, -- serialized key-value pair of non-empty account slots.
PRIMARY KEY (root)
);

-- Create account_vault table
CREATE TABLE account_vault (
root BLOB NOT NULL, -- root of the Merkle tree for the account vault.
assets BLOB NOT NULL -- serialized account vault assets.
-- Create account_vaults table
CREATE TABLE account_vaults (
root BLOB NOT NULL, -- root of the Merkle tree for the account vault.
assets BLOB NOT NULL, -- serialized account vault assets.
PRIMARY KEY (root)
);

-- Update accounts table
-- Create account_keys table
CREATE TABLE account_keys (
account_id UNSIGNED BIG INT NOT NULL, -- ID of the account
key_pair BLOB NOT NULL, -- key pair
PRIMARY KEY (account_id),
FOREIGN KEY (account_id) REFERENCES accounts(id)
);

-- Create accounts table
CREATE TABLE accounts (
id UNSIGNED BIG INT NOT NULL, -- account ID.
code_root BLOB NOT NULL, -- root of the account_code Merkle tree.
storage_root BLOB NOT NULL, -- root of the account_storage Merkle tree.
vault_root BLOB NOT NULL, -- root of the account_vault Merkle tree.
nonce BIGINT NOT NULL, -- account nonce.
committed BOOLEAN NOT NULL -- true if recorded, false if not.
code_root BLOB NOT NULL, -- root of the account_code Merkle tree.
storage_root BLOB NOT NULL, -- root of the account_storage Merkle tree.
vault_root BLOB NOT NULL, -- root of the account_vault Merkle tree.
nonce BIGINT NOT NULL, -- account nonce.
committed BOOLEAN NOT NULL, -- true if recorded, false if not.
PRIMARY KEY (id),
FOREIGN KEY (code_root) REFERENCES account_code(root),
FOREIGN KEY (storage_root) REFERENCES account_storage(root),
FOREIGN KEY (vault_root) REFERENCES account_vaults(root)
);