added singed storage types
This commit is contained in:
parent
b999feee94
commit
800729bad7
|
|
@ -1,7 +1,9 @@
|
||||||
use contractless::blocks::storage_key::{StorageKey, UnsignedStorageKey};
|
use contractless::blocks::storage_key::{StorageKey, UnsignedStorageKey};
|
||||||
use contractless::blocks::storage_values::{
|
use contractless::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
UnsignedStorageBool, UnsignedStorageString, UnsignedStorageU128, UnsignedStorageU16,
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8, UnsignedStorageBool,
|
||||||
|
UnsignedStorageI128, UnsignedStorageI16, UnsignedStorageI32, UnsignedStorageI64,
|
||||||
|
UnsignedStorageI8, UnsignedStorageString, UnsignedStorageU128, UnsignedStorageU16,
|
||||||
UnsignedStorageU32, UnsignedStorageU64, UnsignedStorageU8, STORAGE_KEY_HASH_BYTES,
|
UnsignedStorageU32, UnsignedStorageU64, UnsignedStorageU8, STORAGE_KEY_HASH_BYTES,
|
||||||
STORAGE_STRING_VALUE_BYTES, STORAGE_VALUE_KEY_BYTES,
|
STORAGE_STRING_VALUE_BYTES, STORAGE_VALUE_KEY_BYTES,
|
||||||
};
|
};
|
||||||
|
|
@ -9,7 +11,8 @@ use contractless::common::cli_prompts::{
|
||||||
prompt_hidden_nonempty, prompt_visible, prompt_visible_with_default, prompt_wallet_path,
|
prompt_hidden_nonempty, prompt_visible, prompt_visible_with_default, prompt_wallet_path,
|
||||||
};
|
};
|
||||||
use contractless::common::types::{
|
use contractless::common::types::{
|
||||||
STORAGE_BOOL_TYPE, STORAGE_KEY_FEE, STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE,
|
STORAGE_BOOL_TYPE, STORAGE_I128_TYPE, STORAGE_I16_TYPE, STORAGE_I32_TYPE, STORAGE_I64_TYPE,
|
||||||
|
STORAGE_I8_TYPE, STORAGE_KEY_FEE, STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE,
|
||||||
STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE, STORAGE_VALUE_FEE,
|
STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE, STORAGE_VALUE_FEE,
|
||||||
};
|
};
|
||||||
use contractless::wallets::structures::Wallet;
|
use contractless::wallets::structures::Wallet;
|
||||||
|
|
@ -29,6 +32,11 @@ fn usage() {
|
||||||
println!(" ./data_storage_tx u32|32bit <storage_key_hash> <field_key> <value> [txfee]");
|
println!(" ./data_storage_tx u32|32bit <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
println!(" ./data_storage_tx u64|64bit <storage_key_hash> <field_key> <value> [txfee]");
|
println!(" ./data_storage_tx u64|64bit <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
println!(" ./data_storage_tx u128|128bit <storage_key_hash> <field_key> <value> [txfee]");
|
println!(" ./data_storage_tx u128|128bit <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
|
println!(" ./data_storage_tx i8 <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
|
println!(" ./data_storage_tx i16 <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
|
println!(" ./data_storage_tx i32 <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
|
println!(" ./data_storage_tx i64 <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
|
println!(" ./data_storage_tx i128 <storage_key_hash> <field_key> <value> [txfee]");
|
||||||
println!(
|
println!(
|
||||||
" ./data_storage_tx string <storage_key_hash> <field_key> <value> [previous_hash|0] [txfee]"
|
" ./data_storage_tx string <storage_key_hash> <field_key> <value> [previous_hash|0] [txfee]"
|
||||||
);
|
);
|
||||||
|
|
@ -105,6 +113,11 @@ fn normalize_storage_type(input: &str) -> Option<&'static str> {
|
||||||
"u32" | "32bit" | "32" => Some("u32"),
|
"u32" | "32bit" | "32" => Some("u32"),
|
||||||
"u64" | "64bit" | "64" => Some("u64"),
|
"u64" | "64bit" | "64" => Some("u64"),
|
||||||
"u128" | "128bit" | "128" => Some("u128"),
|
"u128" | "128bit" | "128" => Some("u128"),
|
||||||
|
"i8" | "signed8" | "i8bit" => Some("i8"),
|
||||||
|
"i16" | "signed16" | "i16bit" => Some("i16"),
|
||||||
|
"i32" | "signed32" | "i32bit" => Some("i32"),
|
||||||
|
"i64" | "signed64" | "i64bit" => Some("i64"),
|
||||||
|
"i128" | "signed128" | "i128bit" => Some("i128"),
|
||||||
"string" | "str" | "text" => Some("string"),
|
"string" | "str" | "text" => Some("string"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -275,12 +288,17 @@ macro_rules! create_numeric_storage {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let hash = transaction.$unsigned_field.hash().await;
|
let hash = transaction.$unsigned_field.hash().await;
|
||||||
|
let output_value = if $label.ends_with("128") {
|
||||||
|
serde_json::Value::String(transaction.$unsigned_field.value.to_string())
|
||||||
|
} else {
|
||||||
|
json!(transaction.$unsigned_field.value)
|
||||||
|
};
|
||||||
let output = json!({
|
let output = json!({
|
||||||
"txtype": $txtype,
|
"txtype": $txtype,
|
||||||
"timestamp": $timestamp,
|
"timestamp": $timestamp,
|
||||||
"storagekey": transaction.$unsigned_field.storagekey,
|
"storagekey": transaction.$unsigned_field.storagekey,
|
||||||
"key": transaction.$unsigned_field.key,
|
"key": transaction.$unsigned_field.key,
|
||||||
"value": transaction.$unsigned_field.value,
|
"value": output_value,
|
||||||
"address": address,
|
"address": address,
|
||||||
"txfee": txfee,
|
"txfee": txfee,
|
||||||
"hash": hash,
|
"hash": hash,
|
||||||
|
|
@ -453,7 +471,7 @@ async fn main() {
|
||||||
args[1].clone()
|
args[1].clone()
|
||||||
} else {
|
} else {
|
||||||
prompt_visible(
|
prompt_visible(
|
||||||
"Please enter storage transaction type (create_storage, bool, u8, u16, u32, u64, u128, string): ",
|
"Please enter storage transaction type (create_storage, bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, string): ",
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
|
@ -556,6 +574,81 @@ async fn main() {
|
||||||
"u128"
|
"u128"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
"i8" => {
|
||||||
|
create_numeric_storage!(
|
||||||
|
args,
|
||||||
|
timestamp,
|
||||||
|
wallet,
|
||||||
|
storagekey,
|
||||||
|
key,
|
||||||
|
i8,
|
||||||
|
UnsignedStorageI8,
|
||||||
|
StorageI8,
|
||||||
|
unsigned_storagei8,
|
||||||
|
STORAGE_I8_TYPE,
|
||||||
|
"i8"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"i16" => {
|
||||||
|
create_numeric_storage!(
|
||||||
|
args,
|
||||||
|
timestamp,
|
||||||
|
wallet,
|
||||||
|
storagekey,
|
||||||
|
key,
|
||||||
|
i16,
|
||||||
|
UnsignedStorageI16,
|
||||||
|
StorageI16,
|
||||||
|
unsigned_storagei16,
|
||||||
|
STORAGE_I16_TYPE,
|
||||||
|
"i16"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"i32" => {
|
||||||
|
create_numeric_storage!(
|
||||||
|
args,
|
||||||
|
timestamp,
|
||||||
|
wallet,
|
||||||
|
storagekey,
|
||||||
|
key,
|
||||||
|
i32,
|
||||||
|
UnsignedStorageI32,
|
||||||
|
StorageI32,
|
||||||
|
unsigned_storagei32,
|
||||||
|
STORAGE_I32_TYPE,
|
||||||
|
"i32"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"i64" => {
|
||||||
|
create_numeric_storage!(
|
||||||
|
args,
|
||||||
|
timestamp,
|
||||||
|
wallet,
|
||||||
|
storagekey,
|
||||||
|
key,
|
||||||
|
i64,
|
||||||
|
UnsignedStorageI64,
|
||||||
|
StorageI64,
|
||||||
|
unsigned_storagei64,
|
||||||
|
STORAGE_I64_TYPE,
|
||||||
|
"i64"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"i128" => {
|
||||||
|
create_numeric_storage!(
|
||||||
|
args,
|
||||||
|
timestamp,
|
||||||
|
wallet,
|
||||||
|
storagekey,
|
||||||
|
key,
|
||||||
|
i128,
|
||||||
|
UnsignedStorageI128,
|
||||||
|
StorageI128,
|
||||||
|
unsigned_storagei128,
|
||||||
|
STORAGE_I128_TYPE,
|
||||||
|
"i128"
|
||||||
|
)
|
||||||
|
}
|
||||||
"string" => create_string_storage(&args, timestamp, &wallet, storagekey, key).await,
|
"string" => create_string_storage(&args, timestamp, &wallet, storagekey, key).await,
|
||||||
_ => usage(),
|
_ => usage(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
use contractless::blocks::delete_key::{DeleteKey, UnsignedDeleteKey};
|
||||||
|
use contractless::blocks::storage_values::{STORAGE_KEY_HASH_BYTES, STORAGE_VALUE_KEY_BYTES};
|
||||||
|
use contractless::common::cli_prompts::{
|
||||||
|
prompt_hidden_nonempty, prompt_visible, prompt_visible_with_default, prompt_wallet_path,
|
||||||
|
};
|
||||||
|
use contractless::common::types::{DELETE_KEY_TYPE, STORAGE_VALUE_FEE};
|
||||||
|
use contractless::wallets::structures::Wallet;
|
||||||
|
use contractless::{create_dir_all, decode, env, json, AsyncWriteExt, File, Utc};
|
||||||
|
|
||||||
|
fn display_fee(value: u64) -> f64 {
|
||||||
|
value as f64 / 100_000_000.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_fee(value: &str) -> Option<u64> {
|
||||||
|
let parsed = value.trim().parse::<f64>().ok()?;
|
||||||
|
if parsed.is_sign_negative() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some((parsed * 100_000_000.0).round() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn valid_storage_key_hash(value: &str) -> bool {
|
||||||
|
matches!(decode(value.trim()), Ok(bytes) if bytes.len() == STORAGE_KEY_HASH_BYTES)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fixed_field_key(input: &str) -> Option<String> {
|
||||||
|
let trimmed = input.trim();
|
||||||
|
if trimmed.is_empty() || trimmed.as_bytes().len() > STORAGE_VALUE_KEY_BYTES {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(format!("{trimmed:<STORAGE_VALUE_KEY_BYTES$}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write_transaction(hash: &str, output: &serde_json::Value) -> Result<(), String> {
|
||||||
|
let output = serde_json::to_string_pretty(output)
|
||||||
|
.map_err(|err| format!("Failed to format transaction JSON: {err}"))?;
|
||||||
|
create_dir_all("./transactions")
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to create transactions directory: {err}"))?;
|
||||||
|
let path = format!("./transactions/{hash}.json");
|
||||||
|
let mut file = File::create(&path)
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to create transaction file: {err}"))?;
|
||||||
|
file.write_all(output.as_bytes())
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to write transaction file: {err}"))?;
|
||||||
|
println!("{output}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
let storagekey = if args.len() > 1 {
|
||||||
|
args[1].trim().to_string()
|
||||||
|
} else {
|
||||||
|
prompt_visible("Please enter the storage key hash (32-byte / 64-character hex): ")
|
||||||
|
.await
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
};
|
||||||
|
if !valid_storage_key_hash(&storagekey) {
|
||||||
|
eprintln!("Storage key hash must be a 32-byte / 64-character hex string.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key_input = if args.len() > 2 {
|
||||||
|
args[2].clone()
|
||||||
|
} else {
|
||||||
|
prompt_visible(
|
||||||
|
"Please enter the data key to delete (a base key deletes its scalar value and _00 through _19 chunks): ",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
};
|
||||||
|
let Some(key) = fixed_field_key(&key_input) else {
|
||||||
|
eprintln!("Data key must be 1 to 50 bytes.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let txfee = if args.len() > 3 {
|
||||||
|
match parse_fee(&args[3]) {
|
||||||
|
Some(fee) => fee,
|
||||||
|
None => {
|
||||||
|
eprintln!("Please enter a valid transaction fee.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let default = format!("{:.8}", display_fee(STORAGE_VALUE_FEE));
|
||||||
|
loop {
|
||||||
|
let value =
|
||||||
|
prompt_visible_with_default("Please enter the delete transaction fee", &default)
|
||||||
|
.await;
|
||||||
|
if let Some(fee) = parse_fee(&value) {
|
||||||
|
break fee;
|
||||||
|
}
|
||||||
|
println!("Please enter a valid transaction fee.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if txfee < STORAGE_VALUE_FEE {
|
||||||
|
eprintln!(
|
||||||
|
"Delete transaction fee must be at least {:.8}.",
|
||||||
|
display_fee(STORAGE_VALUE_FEE)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let wallet_path = prompt_wallet_path().await;
|
||||||
|
let wallet_key = prompt_hidden_nonempty(
|
||||||
|
"What is your wallet decryption key? ",
|
||||||
|
"Wallet key cannot be empty. Please try again.",
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let wallet = match Wallet::try_obtain_wallet(wallet_key, Some(&wallet_path)).await {
|
||||||
|
Ok(wallet) => wallet,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Wallet decryption failed: {err}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let address = wallet.saved.short_address.trim().to_string();
|
||||||
|
let timestamp = Utc::now().timestamp() as u32;
|
||||||
|
let unsigned = UnsignedDeleteKey {
|
||||||
|
txtype: DELETE_KEY_TYPE,
|
||||||
|
time: timestamp,
|
||||||
|
storagekey,
|
||||||
|
key,
|
||||||
|
address: address.clone(),
|
||||||
|
txfee,
|
||||||
|
};
|
||||||
|
let transaction = match DeleteKey::new(unsigned.clone(), &wallet.saved.private_key).await {
|
||||||
|
Ok(transaction) => transaction,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to sign delete-key transaction: {err}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let hash = unsigned.hash().await;
|
||||||
|
let output = json!({
|
||||||
|
"txtype": DELETE_KEY_TYPE,
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"storagekey": &unsigned.storagekey,
|
||||||
|
"key": &unsigned.key,
|
||||||
|
"address": address,
|
||||||
|
"txfee": txfee,
|
||||||
|
"hash": hash,
|
||||||
|
"unsigned_deletekey": unsigned,
|
||||||
|
"signature": transaction.signature,
|
||||||
|
});
|
||||||
|
if let Err(err) = write_transaction(&hash, &output).await {
|
||||||
|
eprintln!("{err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -375,6 +375,30 @@ impl Block {
|
||||||
let tx_bytes = storage_tx.to_bytes().await?;
|
let tx_bytes = storage_tx.to_bytes().await?;
|
||||||
buffer.extend_from_slice(&tx_bytes);
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
}
|
}
|
||||||
|
Transaction::StorageI8(storage_tx) => {
|
||||||
|
let tx_bytes = storage_tx.to_bytes().await?;
|
||||||
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
|
}
|
||||||
|
Transaction::StorageI16(storage_tx) => {
|
||||||
|
let tx_bytes = storage_tx.to_bytes().await?;
|
||||||
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
|
}
|
||||||
|
Transaction::StorageI32(storage_tx) => {
|
||||||
|
let tx_bytes = storage_tx.to_bytes().await?;
|
||||||
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
|
}
|
||||||
|
Transaction::StorageI64(storage_tx) => {
|
||||||
|
let tx_bytes = storage_tx.to_bytes().await?;
|
||||||
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
|
}
|
||||||
|
Transaction::StorageI128(storage_tx) => {
|
||||||
|
let tx_bytes = storage_tx.to_bytes().await?;
|
||||||
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
|
}
|
||||||
|
Transaction::DeleteKey(delete_key_tx) => {
|
||||||
|
let tx_bytes = delete_key_tx.to_bytes().await?;
|
||||||
|
buffer.extend_from_slice(&tx_bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod burn;
|
pub mod burn;
|
||||||
pub mod collateral;
|
pub mod collateral;
|
||||||
|
pub mod delete_key;
|
||||||
pub mod genesis;
|
pub mod genesis;
|
||||||
pub mod issue_token;
|
pub mod issue_token;
|
||||||
pub mod loan_payment;
|
pub mod loan_payment;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::blocks::burn::BurnTransaction;
|
use crate::blocks::burn::BurnTransaction;
|
||||||
use crate::blocks::collateral::CollateralClaimTransaction;
|
use crate::blocks::collateral::CollateralClaimTransaction;
|
||||||
|
use crate::blocks::delete_key::DeleteKey;
|
||||||
use crate::blocks::genesis::GenesisTransaction;
|
use crate::blocks::genesis::GenesisTransaction;
|
||||||
use crate::blocks::issue_token::IssueTokenTransaction;
|
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||||
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
||||||
|
|
@ -9,7 +10,8 @@ use crate::blocks::nft::CreateNftTransaction;
|
||||||
use crate::blocks::rewards::RewardsTransaction;
|
use crate::blocks::rewards::RewardsTransaction;
|
||||||
use crate::blocks::storage_key::StorageKey;
|
use crate::blocks::storage_key::StorageKey;
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
||||||
};
|
};
|
||||||
use crate::blocks::swap::SwapTransaction;
|
use crate::blocks::swap::SwapTransaction;
|
||||||
use crate::blocks::token::CreateTokenTransaction;
|
use crate::blocks::token::CreateTokenTransaction;
|
||||||
|
|
@ -40,6 +42,12 @@ pub const STORAGE_U32_TYPE: u8 = 104;
|
||||||
pub const STORAGE_U64_TYPE: u8 = 105;
|
pub const STORAGE_U64_TYPE: u8 = 105;
|
||||||
pub const STORAGE_U128_TYPE: u8 = 106;
|
pub const STORAGE_U128_TYPE: u8 = 106;
|
||||||
pub const STORAGE_STRING_TYPE: u8 = 107;
|
pub const STORAGE_STRING_TYPE: u8 = 107;
|
||||||
|
pub const STORAGE_I8_TYPE: u8 = 108;
|
||||||
|
pub const STORAGE_I16_TYPE: u8 = 109;
|
||||||
|
pub const STORAGE_I32_TYPE: u8 = 110;
|
||||||
|
pub const STORAGE_I64_TYPE: u8 = 111;
|
||||||
|
pub const STORAGE_I128_TYPE: u8 = 112;
|
||||||
|
pub const DELETE_KEY_TYPE: u8 = 113;
|
||||||
|
|
||||||
// Coin and asset names are stored in fixed 15-byte fields.
|
// Coin and asset names are stored in fixed 15-byte fields.
|
||||||
pub const COIN_LENGTH: usize = 15;
|
pub const COIN_LENGTH: usize = 15;
|
||||||
|
|
@ -116,4 +124,10 @@ pub enum Transaction {
|
||||||
StorageU64(StorageU64),
|
StorageU64(StorageU64),
|
||||||
StorageU128(StorageU128),
|
StorageU128(StorageU128),
|
||||||
StorageString(StorageString),
|
StorageString(StorageString),
|
||||||
|
StorageI8(StorageI8),
|
||||||
|
StorageI16(StorageI16),
|
||||||
|
StorageI32(StorageI32),
|
||||||
|
StorageI64(StorageI64),
|
||||||
|
StorageI128(StorageI128),
|
||||||
|
DeleteKey(DeleteKey),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use crate::orphans::undo_transactions::undo_burn::undo_burn_transaction;
|
||||||
use crate::orphans::undo_transactions::undo_collateral::undo_collateral_transaction;
|
use crate::orphans::undo_transactions::undo_collateral::undo_collateral_transaction;
|
||||||
use crate::orphans::undo_transactions::undo_create_nft::undo_create_nft_transaction;
|
use crate::orphans::undo_transactions::undo_create_nft::undo_create_nft_transaction;
|
||||||
use crate::orphans::undo_transactions::undo_create_token::undo_create_token_transaction;
|
use crate::orphans::undo_transactions::undo_create_token::undo_create_token_transaction;
|
||||||
|
use crate::orphans::undo_transactions::undo_delete_key::undo_delete_key_transaction;
|
||||||
use crate::orphans::undo_transactions::undo_issue_token::undo_issue_token_transaction;
|
use crate::orphans::undo_transactions::undo_issue_token::undo_issue_token_transaction;
|
||||||
use crate::orphans::undo_transactions::undo_loan_creation::undo_loan_creation_transaction;
|
use crate::orphans::undo_transactions::undo_loan_creation::undo_loan_creation_transaction;
|
||||||
use crate::orphans::undo_transactions::undo_marketing::undo_marketing_transaction;
|
use crate::orphans::undo_transactions::undo_marketing::undo_marketing_transaction;
|
||||||
|
|
@ -147,7 +148,12 @@ pub async fn undo_transactions(
|
||||||
| Transaction::StorageU32(_)
|
| Transaction::StorageU32(_)
|
||||||
| Transaction::StorageU64(_)
|
| Transaction::StorageU64(_)
|
||||||
| Transaction::StorageU128(_)
|
| Transaction::StorageU128(_)
|
||||||
| Transaction::StorageString(_) => {
|
| Transaction::StorageString(_)
|
||||||
|
| Transaction::StorageI8(_)
|
||||||
|
| Transaction::StorageI16(_)
|
||||||
|
| Transaction::StorageI32(_)
|
||||||
|
| Transaction::StorageI64(_)
|
||||||
|
| Transaction::StorageI128(_) => {
|
||||||
undo_storage_value_transaction(
|
undo_storage_value_transaction(
|
||||||
transaction.clone(),
|
transaction.clone(),
|
||||||
&mining_receiver,
|
&mining_receiver,
|
||||||
|
|
@ -156,6 +162,15 @@ pub async fn undo_transactions(
|
||||||
.await?;
|
.await?;
|
||||||
rolled_back_transactions.push(transaction);
|
rolled_back_transactions.push(transaction);
|
||||||
}
|
}
|
||||||
|
Transaction::DeleteKey(delete_key_tx) => {
|
||||||
|
undo_delete_key_transaction(
|
||||||
|
delete_key_tx.clone(),
|
||||||
|
&mining_receiver,
|
||||||
|
¶ms.db,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
rolled_back_transactions.push(Transaction::DeleteKey(delete_key_tx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The block miner loses one mined-block count when this block is removed.
|
// The block miner loses one mined-block count when this block is removed.
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pub mod undo_burn;
|
||||||
pub mod undo_collateral;
|
pub mod undo_collateral;
|
||||||
pub mod undo_create_nft;
|
pub mod undo_create_nft;
|
||||||
pub mod undo_create_token;
|
pub mod undo_create_token;
|
||||||
|
pub mod undo_delete_key;
|
||||||
pub mod undo_issue_token;
|
pub mod undo_issue_token;
|
||||||
pub mod undo_loan_creation;
|
pub mod undo_loan_creation;
|
||||||
pub mod undo_marketing;
|
pub mod undo_marketing;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::blocks::burn::BurnTransaction;
|
use crate::blocks::burn::BurnTransaction;
|
||||||
use crate::blocks::collateral::CollateralClaimTransaction;
|
use crate::blocks::collateral::CollateralClaimTransaction;
|
||||||
|
use crate::blocks::delete_key::DeleteKey;
|
||||||
use crate::blocks::issue_token::IssueTokenTransaction;
|
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||||
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
||||||
use crate::blocks::loans::LoanContractTransaction;
|
use crate::blocks::loans::LoanContractTransaction;
|
||||||
|
|
@ -346,6 +347,19 @@ where
|
||||||
restore_if_spendable(tx_label, "unknown", &[signature], spendable, insert).await;
|
restore_if_spendable(tx_label, "unknown", &[signature], spendable, insert).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn restore_delete_key(transaction: &DeleteKey, db: &Db) {
|
||||||
|
let delete = &transaction.unsigned_deletekey;
|
||||||
|
let spendable = balance_checkup(db, 0, delete.txfee, BASECOIN.clone(), &delete.address).await;
|
||||||
|
restore_if_spendable(
|
||||||
|
"delete_key",
|
||||||
|
"unknown",
|
||||||
|
std::slice::from_ref(&transaction.signature),
|
||||||
|
spendable,
|
||||||
|
|| async { transaction.add_to_memory().await },
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn restore_rolled_back_transaction(transaction: &Transaction, db: &Db) {
|
pub async fn restore_rolled_back_transaction(transaction: &Transaction, db: &Db) {
|
||||||
match transaction {
|
match transaction {
|
||||||
Transaction::Transfer(tx) => restore_transfer(tx, db).await,
|
Transaction::Transfer(tx) => restore_transfer(tx, db).await,
|
||||||
|
|
@ -393,6 +407,28 @@ pub async fn restore_rolled_back_transaction(transaction: &Transaction, db: &Db)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
Transaction::StorageI8(tx) => {
|
||||||
|
restore_storage_value("storage_i8", tx, db, || async { tx.add_to_memory().await }).await
|
||||||
|
}
|
||||||
|
Transaction::StorageI16(tx) => {
|
||||||
|
restore_storage_value("storage_i16", tx, db, || async { tx.add_to_memory().await })
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Transaction::StorageI32(tx) => {
|
||||||
|
restore_storage_value("storage_i32", tx, db, || async { tx.add_to_memory().await })
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Transaction::StorageI64(tx) => {
|
||||||
|
restore_storage_value("storage_i64", tx, db, || async { tx.add_to_memory().await })
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Transaction::StorageI128(tx) => {
|
||||||
|
restore_storage_value("storage_i128", tx, db, || async {
|
||||||
|
tx.add_to_memory().await
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Transaction::DeleteKey(tx) => restore_delete_key(tx, db).await,
|
||||||
Transaction::Genesis(_) | Transaction::Rewards(_) => {}
|
Transaction::Genesis(_) | Transaction::Rewards(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
use crate::blocks::delete_key::{delete_record_keys, delete_rollback_key, DeleteKey};
|
||||||
|
use crate::common::types::STORAGE_VALUE_ROLLBACK_TREE;
|
||||||
|
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
|
||||||
|
use crate::records::memory::mempool::BASECOIN;
|
||||||
|
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
|
||||||
|
use crate::{decode, sled::Db};
|
||||||
|
|
||||||
|
pub async fn undo_delete_key_transaction(
|
||||||
|
transaction: DeleteKey,
|
||||||
|
mining_receiver: &str,
|
||||||
|
db: &Db,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let delete = &transaction.unsigned_deletekey;
|
||||||
|
let storage_tree_name = decode(&delete.storagekey)
|
||||||
|
.map_err(|err| format!("Could not decode delete-key storage tree during undo: {err}"))?;
|
||||||
|
let txhash = delete.hash().await;
|
||||||
|
let txhash_bytes = decode(&txhash)
|
||||||
|
.map_err(|err| format!("Could not decode delete-key txhash during undo: {err}"))?;
|
||||||
|
let targets = delete_record_keys(&delete.address, &delete.key)?;
|
||||||
|
|
||||||
|
let _ = balance_sheet_operation_with_db(
|
||||||
|
db,
|
||||||
|
mining_receiver,
|
||||||
|
delete.txfee,
|
||||||
|
&BASECOIN,
|
||||||
|
"subtraction",
|
||||||
|
);
|
||||||
|
let _ =
|
||||||
|
balance_sheet_operation_with_db(db, &delete.address, delete.txfee, &BASECOIN, "addition");
|
||||||
|
|
||||||
|
let rollback_tree = db
|
||||||
|
.open_tree(STORAGE_VALUE_ROLLBACK_TREE)
|
||||||
|
.map_err(|err| format!("Could not open delete-key rollback tree: {err}"))?;
|
||||||
|
let storage_tree = db
|
||||||
|
.open_tree(storage_tree_name)
|
||||||
|
.map_err(|err| format!("Could not open storage tree during delete-key undo: {err}"))?;
|
||||||
|
|
||||||
|
for (target_index, target) in targets.into_iter().enumerate() {
|
||||||
|
let rollback_key = delete_rollback_key(&txhash_bytes, target_index)?;
|
||||||
|
let rollback_value = rollback_tree
|
||||||
|
.get(&rollback_key)
|
||||||
|
.map_err(|err| format!("Could not read delete-key rollback value: {err}"))?
|
||||||
|
.ok_or_else(|| "Missing delete-key rollback record.".to_string())?;
|
||||||
|
match rollback_value.first().copied() {
|
||||||
|
Some(0) => {
|
||||||
|
storage_tree
|
||||||
|
.remove(&target)
|
||||||
|
.map_err(|err| format!("Could not preserve absent deleted value: {err}"))?;
|
||||||
|
}
|
||||||
|
Some(1) => {
|
||||||
|
storage_tree
|
||||||
|
.insert(&target, &rollback_value[1..])
|
||||||
|
.map_err(|err| format!("Could not restore deleted storage value: {err}"))?;
|
||||||
|
}
|
||||||
|
_ => return Err("Invalid delete-key rollback marker.".to_string()),
|
||||||
|
}
|
||||||
|
rollback_tree
|
||||||
|
.remove(rollback_key)
|
||||||
|
.map_err(|err| format!("Could not remove delete-key rollback record: {err}"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = remove_wallet_transaction_index(db, &[&delete.address, mining_receiver], &txhash_bytes);
|
||||||
|
db.open_tree("txid")
|
||||||
|
.map_err(|err| format!("Could not open txid tree during delete-key undo: {err}"))?
|
||||||
|
.remove(txhash_bytes)
|
||||||
|
.map_err(|err| format!("Could not remove delete-key txid mapping: {err}"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,11 @@ fn storage_undo_parts(transaction: &Transaction) -> Result<StorageUndoParts, Str
|
||||||
Transaction::StorageU64(tx) => tx.storage_parts(),
|
Transaction::StorageU64(tx) => tx.storage_parts(),
|
||||||
Transaction::StorageU128(tx) => tx.storage_parts(),
|
Transaction::StorageU128(tx) => tx.storage_parts(),
|
||||||
Transaction::StorageString(tx) => tx.storage_parts(),
|
Transaction::StorageString(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI8(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI16(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI32(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI64(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI128(tx) => tx.storage_parts(),
|
||||||
_ => return Err("Unsupported storage value transaction undo.".to_string()),
|
_ => return Err("Unsupported storage value transaction undo.".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::blocks::delete_key::{delete_record_keys, delete_rollback_key, DeleteKey};
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
storage_record_key, storage_string_record_key, StorageBool, StorageString, StorageU128,
|
storage_record_key, storage_string_record_key, StorageBool, StorageI128, StorageI16,
|
||||||
StorageU16, StorageU32, StorageU64, StorageU8, StorageValueTransaction,
|
StorageI32, StorageI64, StorageI8, StorageString, StorageU128, StorageU16, StorageU32,
|
||||||
|
StorageU64, StorageU8, StorageValueTransaction,
|
||||||
};
|
};
|
||||||
use crate::common::types::{
|
use crate::common::types::{
|
||||||
Transaction, STORAGE_BOOL_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE,
|
Transaction, DELETE_KEY_TYPE, STORAGE_BOOL_TYPE, STORAGE_I128_TYPE, STORAGE_I16_TYPE,
|
||||||
STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE,
|
STORAGE_I32_TYPE, STORAGE_I64_TYPE, STORAGE_I8_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE,
|
||||||
|
STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE,
|
||||||
};
|
};
|
||||||
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
|
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
|
||||||
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
|
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
|
||||||
|
|
@ -43,6 +46,24 @@ async fn storage_value_transaction_from_original(original: &[u8]) -> Result<Tran
|
||||||
STORAGE_STRING_TYPE => Ok(Transaction::StorageString(
|
STORAGE_STRING_TYPE => Ok(Transaction::StorageString(
|
||||||
StorageString::from_bytes(txtype, body).await?,
|
StorageString::from_bytes(txtype, body).await?,
|
||||||
)),
|
)),
|
||||||
|
STORAGE_I8_TYPE => Ok(Transaction::StorageI8(
|
||||||
|
StorageI8::from_bytes(txtype, body).await?,
|
||||||
|
)),
|
||||||
|
STORAGE_I16_TYPE => Ok(Transaction::StorageI16(
|
||||||
|
StorageI16::from_bytes(txtype, body).await?,
|
||||||
|
)),
|
||||||
|
STORAGE_I32_TYPE => Ok(Transaction::StorageI32(
|
||||||
|
StorageI32::from_bytes(txtype, body).await?,
|
||||||
|
)),
|
||||||
|
STORAGE_I64_TYPE => Ok(Transaction::StorageI64(
|
||||||
|
StorageI64::from_bytes(txtype, body).await?,
|
||||||
|
)),
|
||||||
|
STORAGE_I128_TYPE => Ok(Transaction::StorageI128(
|
||||||
|
StorageI128::from_bytes(txtype, body).await?,
|
||||||
|
)),
|
||||||
|
DELETE_KEY_TYPE => Ok(Transaction::DeleteKey(
|
||||||
|
DeleteKey::from_bytes(txtype, body).await?,
|
||||||
|
)),
|
||||||
_ => Err(anyhow!(
|
_ => Err(anyhow!(
|
||||||
"Unsupported storage value transaction type {txtype}"
|
"Unsupported storage value transaction type {txtype}"
|
||||||
)),
|
)),
|
||||||
|
|
@ -58,6 +79,11 @@ fn selected_storage_value_parts(transaction: &Transaction) -> Result<SelectedSto
|
||||||
Transaction::StorageU64(tx) => tx.storage_parts(),
|
Transaction::StorageU64(tx) => tx.storage_parts(),
|
||||||
Transaction::StorageU128(tx) => tx.storage_parts(),
|
Transaction::StorageU128(tx) => tx.storage_parts(),
|
||||||
Transaction::StorageString(tx) => tx.storage_parts(),
|
Transaction::StorageString(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI8(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI16(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI32(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI64(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI128(tx) => tx.storage_parts(),
|
||||||
_ => return Err(anyhow!("Unsupported storage value transaction")),
|
_ => return Err(anyhow!("Unsupported storage value transaction")),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -77,6 +103,11 @@ fn selected_storage_value_bytes(transaction: &Transaction) -> Result<Vec<u8>> {
|
||||||
Transaction::StorageU64(tx) => tx.storage_value_bytes(),
|
Transaction::StorageU64(tx) => tx.storage_value_bytes(),
|
||||||
Transaction::StorageU128(tx) => tx.storage_value_bytes(),
|
Transaction::StorageU128(tx) => tx.storage_value_bytes(),
|
||||||
Transaction::StorageString(tx) => tx.storage_value_bytes(),
|
Transaction::StorageString(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI8(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI16(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI32(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI64(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI128(tx) => tx.storage_value_bytes(),
|
||||||
_ => Err("Unsupported storage value transaction".to_string()),
|
_ => Err("Unsupported storage value transaction".to_string()),
|
||||||
}
|
}
|
||||||
.map_err(|err| anyhow!(err))
|
.map_err(|err| anyhow!(err))
|
||||||
|
|
@ -1110,24 +1141,40 @@ pub async fn apply_selected_transaction_math(
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let transaction = storage_value_transaction_from_original(original).await?;
|
let transaction = storage_value_transaction_from_original(original).await?;
|
||||||
let parts = selected_storage_value_parts(&transaction)?;
|
|
||||||
let storage_tree = decode(&parts.storagekey)?;
|
|
||||||
let txhash_bytes = decode(hash)?;
|
let txhash_bytes = decode(hash)?;
|
||||||
let storage_record_key = match &transaction {
|
if let Transaction::DeleteKey(tx) = &transaction {
|
||||||
Transaction::StorageString(tx) => storage_string_record_key(db, tx)
|
let delete = &tx.unsigned_deletekey;
|
||||||
.await
|
let storage_tree = decode(&delete.storagekey)?;
|
||||||
.map_err(|err| anyhow!(err))?,
|
for (target_index, target) in delete_record_keys(&delete.address, &delete.key)
|
||||||
_ => storage_record_key(&parts.address, &parts.key)
|
.map_err(|err| anyhow!(err))?
|
||||||
.map_err(|err| anyhow!(err))?,
|
.into_iter()
|
||||||
};
|
.enumerate()
|
||||||
let value_bytes = selected_storage_value_bytes(&transaction)?;
|
{
|
||||||
|
pending_effects.remove_dynamic_tree(
|
||||||
pending_effects.set_dynamic_tree(
|
storage_tree.clone(),
|
||||||
storage_tree,
|
target,
|
||||||
storage_record_key,
|
delete_rollback_key(&txhash_bytes, target_index)
|
||||||
value_bytes,
|
.map_err(|err| anyhow!(err))?,
|
||||||
txhash_bytes.clone(),
|
);
|
||||||
);
|
}
|
||||||
|
} else {
|
||||||
|
let parts = selected_storage_value_parts(&transaction)?;
|
||||||
|
let storage_tree = decode(&parts.storagekey)?;
|
||||||
|
let storage_record_key = match &transaction {
|
||||||
|
Transaction::StorageString(tx) => storage_string_record_key(db, tx)
|
||||||
|
.await
|
||||||
|
.map_err(|err| anyhow!(err))?,
|
||||||
|
_ => storage_record_key(&parts.address, &parts.key)
|
||||||
|
.map_err(|err| anyhow!(err))?,
|
||||||
|
};
|
||||||
|
let value_bytes = selected_storage_value_bytes(&transaction)?;
|
||||||
|
pending_effects.set_dynamic_tree(
|
||||||
|
storage_tree,
|
||||||
|
storage_record_key,
|
||||||
|
value_bytes,
|
||||||
|
txhash_bytes.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
add_balance_change(db, &mut balance_changes, address, &BASECOIN, -*fee);
|
add_balance_change(db, &mut balance_changes, address, &BASECOIN, -*fee);
|
||||||
add_balance_change_bytes(
|
add_balance_change_bytes(
|
||||||
&mut balance_changes,
|
&mut balance_changes,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
use crate::blocks::delete_key::{delete_record_keys, delete_rollback_key, DeleteKey};
|
||||||
|
use crate::decode;
|
||||||
|
use crate::records::memory::mempool::BASECOIN;
|
||||||
|
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
|
||||||
|
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
|
||||||
|
use crate::{Arc, Mutex};
|
||||||
|
|
||||||
|
pub async fn process_delete_key(
|
||||||
|
transaction: &DeleteKey,
|
||||||
|
mut binary_data: Vec<u8>,
|
||||||
|
index_counter: Arc<Mutex<&mut usize>>,
|
||||||
|
miner: String,
|
||||||
|
block_header_number: u32,
|
||||||
|
pending_effects: &mut PendingEffects,
|
||||||
|
) -> Result<Vec<u8>, String> {
|
||||||
|
let mut index = index_counter.lock().await;
|
||||||
|
**index += 1;
|
||||||
|
|
||||||
|
let delete = &transaction.unsigned_deletekey;
|
||||||
|
let storage_tree = decode(&delete.storagekey)
|
||||||
|
.map_err(|err| format!("Could not decode delete-key storage tree: {err}"))?;
|
||||||
|
let txhash = delete.hash().await;
|
||||||
|
let txhash_bytes =
|
||||||
|
decode(&txhash).map_err(|err| format!("Could not decode delete-key txhash: {err}"))?;
|
||||||
|
let targets = delete_record_keys(&delete.address, &delete.key)?;
|
||||||
|
|
||||||
|
binary_data.extend(
|
||||||
|
transaction
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Could not serialize delete-key transaction: {err}"))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (target_index, target) in targets.into_iter().enumerate() {
|
||||||
|
pending_effects.remove_dynamic_tree(
|
||||||
|
storage_tree.clone(),
|
||||||
|
target,
|
||||||
|
delete_rollback_key(&txhash_bytes, target_index)?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pending_effects.add_balance(&miner, delete.txfee, &BASECOIN, BalanceOperand::Addition);
|
||||||
|
pending_effects.add_balance(
|
||||||
|
&delete.address,
|
||||||
|
delete.txfee,
|
||||||
|
&BASECOIN,
|
||||||
|
BalanceOperand::Subtraction,
|
||||||
|
);
|
||||||
|
|
||||||
|
let txvalue = format!("{block_header_number}:{}", **index);
|
||||||
|
pending_effects.set_tree("txid", txhash_bytes.clone(), txvalue.into_bytes());
|
||||||
|
index_wallet_transaction(
|
||||||
|
pending_effects,
|
||||||
|
&[&delete.address],
|
||||||
|
block_header_number,
|
||||||
|
**index as u32,
|
||||||
|
&txhash_bytes,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(binary_data)
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ pub mod add_payments_db;
|
||||||
pub mod borrower_tx;
|
pub mod borrower_tx;
|
||||||
pub mod burn_tx;
|
pub mod burn_tx;
|
||||||
pub mod collateral_tx;
|
pub mod collateral_tx;
|
||||||
|
pub mod delete_key_tx;
|
||||||
pub mod genesis_tx;
|
pub mod genesis_tx;
|
||||||
pub mod header_number;
|
pub mod header_number;
|
||||||
pub mod issue_token_tx;
|
pub mod issue_token_tx;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::common::types::Transaction;
|
||||||
use crate::records::record_chain::borrower_tx::process_borrower;
|
use crate::records::record_chain::borrower_tx::process_borrower;
|
||||||
use crate::records::record_chain::burn_tx::process_burn;
|
use crate::records::record_chain::burn_tx::process_burn;
|
||||||
use crate::records::record_chain::collateral_tx::process_collateral;
|
use crate::records::record_chain::collateral_tx::process_collateral;
|
||||||
|
use crate::records::record_chain::delete_key_tx::process_delete_key;
|
||||||
use crate::records::record_chain::genesis_tx::process_genesis;
|
use crate::records::record_chain::genesis_tx::process_genesis;
|
||||||
use crate::records::record_chain::issue_token_tx::process_issue_token;
|
use crate::records::record_chain::issue_token_tx::process_issue_token;
|
||||||
use crate::records::record_chain::lender_tx::process_lender;
|
use crate::records::record_chain::lender_tx::process_lender;
|
||||||
|
|
@ -208,7 +209,12 @@ pub async fn handle_transactions(
|
||||||
| Transaction::StorageU32(_)
|
| Transaction::StorageU32(_)
|
||||||
| Transaction::StorageU64(_)
|
| Transaction::StorageU64(_)
|
||||||
| Transaction::StorageU128(_)
|
| Transaction::StorageU128(_)
|
||||||
| Transaction::StorageString(_) => {
|
| Transaction::StorageString(_)
|
||||||
|
| Transaction::StorageI8(_)
|
||||||
|
| Transaction::StorageI16(_)
|
||||||
|
| Transaction::StorageI32(_)
|
||||||
|
| Transaction::StorageI64(_)
|
||||||
|
| Transaction::StorageI128(_) => {
|
||||||
process_storage_value(
|
process_storage_value(
|
||||||
transaction,
|
transaction,
|
||||||
binary_data.clone(),
|
binary_data.clone(),
|
||||||
|
|
@ -220,6 +226,17 @@ pub async fn handle_transactions(
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
Transaction::DeleteKey(delete_key_transaction) => {
|
||||||
|
process_delete_key(
|
||||||
|
delete_key_transaction,
|
||||||
|
binary_data.clone(),
|
||||||
|
index_mutex.clone(),
|
||||||
|
miner.clone(),
|
||||||
|
block_header_number,
|
||||||
|
pending_effects,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
Ok(new_binary_data) => {
|
Ok(new_binary_data) => {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,11 @@ pub enum PendingEffect {
|
||||||
value: Vec<u8>,
|
value: Vec<u8>,
|
||||||
rollback_key: Vec<u8>,
|
rollback_key: Vec<u8>,
|
||||||
},
|
},
|
||||||
|
DynamicTreeRemove {
|
||||||
|
tree: Vec<u8>,
|
||||||
|
key: Vec<u8>,
|
||||||
|
rollback_key: Vec<u8>,
|
||||||
|
},
|
||||||
TreeRemove {
|
TreeRemove {
|
||||||
tree: &'static str,
|
tree: &'static str,
|
||||||
key: Vec<u8>,
|
key: Vec<u8>,
|
||||||
|
|
@ -133,6 +138,14 @@ impl PendingEffects {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_dynamic_tree(&mut self, tree: Vec<u8>, key: Vec<u8>, rollback_key: Vec<u8>) {
|
||||||
|
self.push(PendingEffect::DynamicTreeRemove {
|
||||||
|
tree,
|
||||||
|
key,
|
||||||
|
rollback_key,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_tree(&mut self, tree: &'static str, key: Vec<u8>) {
|
pub fn remove_tree(&mut self, tree: &'static str, key: Vec<u8>) {
|
||||||
self.push(PendingEffect::TreeRemove { tree, key });
|
self.push(PendingEffect::TreeRemove { tree, key });
|
||||||
}
|
}
|
||||||
|
|
@ -337,6 +350,39 @@ fn apply_effect(db: &Db, effect: &PendingEffect) -> Result<AppliedEffect, String
|
||||||
previous_rollback,
|
previous_rollback,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
PendingEffect::DynamicTreeRemove {
|
||||||
|
tree,
|
||||||
|
key,
|
||||||
|
rollback_key,
|
||||||
|
} => {
|
||||||
|
let tree_handle = db
|
||||||
|
.open_tree(tree)
|
||||||
|
.map_err(|err| format!("Failed to open dynamic storage tree: {err}"))?;
|
||||||
|
let previous = tree_handle
|
||||||
|
.remove(key)
|
||||||
|
.map_err(|err| format!("Failed to remove dynamic storage value: {err}"))?
|
||||||
|
.map(|value| value.to_vec());
|
||||||
|
let rollback_tree = db
|
||||||
|
.open_tree(STORAGE_VALUE_ROLLBACK_TREE)
|
||||||
|
.map_err(|err| format!("Failed to open storage value rollback tree: {err}"))?;
|
||||||
|
let previous_rollback = rollback_tree
|
||||||
|
.get(rollback_key)
|
||||||
|
.map_err(|err| format!("Failed to read previous storage rollback value: {err}"))?
|
||||||
|
.map(|value| value.to_vec());
|
||||||
|
rollback_tree
|
||||||
|
.insert(
|
||||||
|
rollback_key,
|
||||||
|
encode_storage_rollback_value(previous.as_deref()),
|
||||||
|
)
|
||||||
|
.map_err(|err| format!("Failed to write storage rollback value: {err}"))?;
|
||||||
|
Ok(AppliedEffect::DynamicTreeMutation {
|
||||||
|
tree: tree.clone(),
|
||||||
|
key: key.clone(),
|
||||||
|
previous,
|
||||||
|
rollback_key: rollback_key.clone(),
|
||||||
|
previous_rollback,
|
||||||
|
})
|
||||||
|
}
|
||||||
PendingEffect::TreeRemove { tree, key } => {
|
PendingEffect::TreeRemove { tree, key } => {
|
||||||
let tree_handle = db
|
let tree_handle = db
|
||||||
.open_tree(tree)
|
.open_tree(tree)
|
||||||
|
|
@ -606,6 +652,71 @@ fn encode_storage_rollback_value(previous: Option<&[u8]>) -> Vec<u8> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dynamic_tree_remove_is_reversible() {
|
||||||
|
let db = crate::sled::Config::new()
|
||||||
|
.temporary(true)
|
||||||
|
.open()
|
||||||
|
.expect("temporary sled database should open");
|
||||||
|
let tree_name = vec![7_u8; 32];
|
||||||
|
let record_key = b"wallet-and-data-key".to_vec();
|
||||||
|
let record_value = b"stored-value".to_vec();
|
||||||
|
let rollback_key = vec![9_u8; 33];
|
||||||
|
db.open_tree(tree_name.clone())
|
||||||
|
.unwrap()
|
||||||
|
.insert(&record_key, record_value.as_slice())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut pending = PendingEffects::default();
|
||||||
|
pending.remove_dynamic_tree(tree_name.clone(), record_key.clone(), rollback_key.clone());
|
||||||
|
let mut applied = pending.apply(&db).expect("remove effect should apply");
|
||||||
|
|
||||||
|
assert!(db
|
||||||
|
.open_tree(tree_name.clone())
|
||||||
|
.unwrap()
|
||||||
|
.get(&record_key)
|
||||||
|
.unwrap()
|
||||||
|
.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
db.open_tree(STORAGE_VALUE_ROLLBACK_TREE)
|
||||||
|
.unwrap()
|
||||||
|
.get(&rollback_key)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref(),
|
||||||
|
[1_u8]
|
||||||
|
.iter()
|
||||||
|
.chain(record_value.iter())
|
||||||
|
.copied()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.as_slice()
|
||||||
|
);
|
||||||
|
|
||||||
|
applied
|
||||||
|
.rollback(&db)
|
||||||
|
.expect("remove effect should roll back");
|
||||||
|
assert_eq!(
|
||||||
|
db.open_tree(tree_name)
|
||||||
|
.unwrap()
|
||||||
|
.get(record_key)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref(),
|
||||||
|
record_value.as_slice()
|
||||||
|
);
|
||||||
|
assert!(db
|
||||||
|
.open_tree(STORAGE_VALUE_ROLLBACK_TREE)
|
||||||
|
.unwrap()
|
||||||
|
.get(rollback_key)
|
||||||
|
.unwrap()
|
||||||
|
.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn append_tree_value(
|
fn append_tree_value(
|
||||||
db: &Db,
|
db: &Db,
|
||||||
tree: &'static str,
|
tree: &'static str,
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,26 @@ async fn storage_transaction_bytes(transaction: &Transaction) -> Result<Vec<u8>,
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| format!("Could not serialize storage string transaction: {err}")),
|
.map_err(|err| format!("Could not serialize storage string transaction: {err}")),
|
||||||
|
Transaction::StorageI8(tx) => tx
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Could not serialize storage i8 transaction: {err}")),
|
||||||
|
Transaction::StorageI16(tx) => tx
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Could not serialize storage i16 transaction: {err}")),
|
||||||
|
Transaction::StorageI32(tx) => tx
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Could not serialize storage i32 transaction: {err}")),
|
||||||
|
Transaction::StorageI64(tx) => tx
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Could not serialize storage i64 transaction: {err}")),
|
||||||
|
Transaction::StorageI128(tx) => tx
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Could not serialize storage i128 transaction: {err}")),
|
||||||
_ => Err("Unsupported storage value transaction.".to_string()),
|
_ => Err("Unsupported storage value transaction.".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +81,11 @@ fn storage_parts(transaction: &Transaction) -> Result<OwnedStorageParts, String>
|
||||||
Transaction::StorageU64(tx) => tx.storage_parts(),
|
Transaction::StorageU64(tx) => tx.storage_parts(),
|
||||||
Transaction::StorageU128(tx) => tx.storage_parts(),
|
Transaction::StorageU128(tx) => tx.storage_parts(),
|
||||||
Transaction::StorageString(tx) => tx.storage_parts(),
|
Transaction::StorageString(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI8(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI16(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI32(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI64(tx) => tx.storage_parts(),
|
||||||
|
Transaction::StorageI128(tx) => tx.storage_parts(),
|
||||||
_ => return Err("Unsupported storage value transaction.".to_string()),
|
_ => return Err("Unsupported storage value transaction.".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -82,6 +107,11 @@ fn storage_value_bytes(transaction: &Transaction) -> Result<Vec<u8>, String> {
|
||||||
Transaction::StorageU64(tx) => tx.storage_value_bytes(),
|
Transaction::StorageU64(tx) => tx.storage_value_bytes(),
|
||||||
Transaction::StorageU128(tx) => tx.storage_value_bytes(),
|
Transaction::StorageU128(tx) => tx.storage_value_bytes(),
|
||||||
Transaction::StorageString(tx) => tx.storage_value_bytes(),
|
Transaction::StorageString(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI8(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI16(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI32(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI64(tx) => tx.storage_value_bytes(),
|
||||||
|
Transaction::StorageI128(tx) => tx.storage_value_bytes(),
|
||||||
_ => Err("Unsupported storage value transaction.".to_string()),
|
_ => Err("Unsupported storage value transaction.".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::blocks::block::{Block, VrfBlock, VRF_BLOCK_BYTES};
|
use crate::blocks::block::{Block, VrfBlock, VRF_BLOCK_BYTES};
|
||||||
use crate::blocks::burn::BurnTransaction;
|
use crate::blocks::burn::BurnTransaction;
|
||||||
use crate::blocks::collateral::CollateralClaimTransaction;
|
use crate::blocks::collateral::CollateralClaimTransaction;
|
||||||
|
use crate::blocks::delete_key::DeleteKey;
|
||||||
use crate::blocks::genesis::GenesisTransaction;
|
use crate::blocks::genesis::GenesisTransaction;
|
||||||
use crate::blocks::issue_token::IssueTokenTransaction;
|
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||||
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
||||||
|
|
@ -10,7 +11,8 @@ use crate::blocks::nft::CreateNftTransaction;
|
||||||
use crate::blocks::rewards::RewardsTransaction;
|
use crate::blocks::rewards::RewardsTransaction;
|
||||||
use crate::blocks::storage_key::StorageKey;
|
use crate::blocks::storage_key::StorageKey;
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
||||||
};
|
};
|
||||||
use crate::blocks::swap::SwapTransaction;
|
use crate::blocks::swap::SwapTransaction;
|
||||||
use crate::blocks::token::CreateTokenTransaction;
|
use crate::blocks::token::CreateTokenTransaction;
|
||||||
|
|
@ -18,9 +20,11 @@ use crate::blocks::transfer::TransferTransaction;
|
||||||
use crate::blocks::vanity::VanityAddressTransaction;
|
use crate::blocks::vanity::VanityAddressTransaction;
|
||||||
use crate::common::types::{
|
use crate::common::types::{
|
||||||
Transaction, BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE,
|
Transaction, BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE,
|
||||||
GENESIS_TYPE, ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, REWARDS_TYPE, STORAGE_BOOL_TYPE,
|
DELETE_KEY_TYPE, GENESIS_TYPE, ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, REWARDS_TYPE,
|
||||||
STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE, STORAGE_U32_TYPE,
|
STORAGE_BOOL_TYPE, STORAGE_I128_TYPE, STORAGE_I16_TYPE, STORAGE_I32_TYPE, STORAGE_I64_TYPE,
|
||||||
STORAGE_U64_TYPE, STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE,
|
STORAGE_I8_TYPE, STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE,
|
||||||
|
STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE,
|
||||||
|
VANITY_ADDRESS_TYPE,
|
||||||
};
|
};
|
||||||
use crate::rpc::command_maps::get_bytes;
|
use crate::rpc::command_maps::get_bytes;
|
||||||
|
|
||||||
|
|
@ -269,6 +273,60 @@ pub async fn load_block_from_binary(binary_data: &[u8]) -> Result<Block, String>
|
||||||
i += body_len;
|
i += body_len;
|
||||||
storage
|
storage
|
||||||
}
|
}
|
||||||
|
STORAGE_I8_TYPE => {
|
||||||
|
let storage = Transaction::StorageI8(
|
||||||
|
StorageI8::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I16_TYPE => {
|
||||||
|
let storage = Transaction::StorageI16(
|
||||||
|
StorageI16::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I32_TYPE => {
|
||||||
|
let storage = Transaction::StorageI32(
|
||||||
|
StorageI32::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I64_TYPE => {
|
||||||
|
let storage = Transaction::StorageI64(
|
||||||
|
StorageI64::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I128_TYPE => {
|
||||||
|
let storage = Transaction::StorageI128(
|
||||||
|
StorageI128::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
DELETE_KEY_TYPE => {
|
||||||
|
let delete_key = Transaction::DeleteKey(
|
||||||
|
DeleteKey::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
delete_key
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(format!("Unsupported transaction type: {txtype}"));
|
return Err(format!("Unsupported transaction type: {txtype}"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::blocks::block::{Block, VrfBlock, VRF_BLOCK_BYTES};
|
use crate::blocks::block::{Block, VrfBlock, VRF_BLOCK_BYTES};
|
||||||
use crate::blocks::burn::BurnTransaction;
|
use crate::blocks::burn::BurnTransaction;
|
||||||
use crate::blocks::collateral::CollateralClaimTransaction;
|
use crate::blocks::collateral::CollateralClaimTransaction;
|
||||||
|
use crate::blocks::delete_key::DeleteKey;
|
||||||
use crate::blocks::genesis::GenesisTransaction;
|
use crate::blocks::genesis::GenesisTransaction;
|
||||||
use crate::blocks::issue_token::IssueTokenTransaction;
|
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||||
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
||||||
|
|
@ -10,7 +11,8 @@ use crate::blocks::nft::CreateNftTransaction;
|
||||||
use crate::blocks::rewards::RewardsTransaction;
|
use crate::blocks::rewards::RewardsTransaction;
|
||||||
use crate::blocks::storage_key::StorageKey;
|
use crate::blocks::storage_key::StorageKey;
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
||||||
};
|
};
|
||||||
use crate::blocks::swap::SwapTransaction;
|
use crate::blocks::swap::SwapTransaction;
|
||||||
use crate::blocks::token::CreateTokenTransaction;
|
use crate::blocks::token::CreateTokenTransaction;
|
||||||
|
|
@ -19,9 +21,11 @@ use crate::blocks::vanity::VanityAddressTransaction;
|
||||||
use crate::common::network_paths_and_settings::block_extension_and_paths;
|
use crate::common::network_paths_and_settings::block_extension_and_paths;
|
||||||
use crate::common::types::{
|
use crate::common::types::{
|
||||||
Transaction, BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE,
|
Transaction, BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE,
|
||||||
GENESIS_TYPE, ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, REWARDS_TYPE, STORAGE_BOOL_TYPE,
|
DELETE_KEY_TYPE, GENESIS_TYPE, ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, REWARDS_TYPE,
|
||||||
STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE, STORAGE_U32_TYPE,
|
STORAGE_BOOL_TYPE, STORAGE_I128_TYPE, STORAGE_I16_TYPE, STORAGE_I32_TYPE, STORAGE_I64_TYPE,
|
||||||
STORAGE_U64_TYPE, STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE,
|
STORAGE_I8_TYPE, STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE,
|
||||||
|
STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE,
|
||||||
|
VANITY_ADDRESS_TYPE,
|
||||||
};
|
};
|
||||||
use crate::fs;
|
use crate::fs;
|
||||||
use crate::rpc::command_maps::get_bytes;
|
use crate::rpc::command_maps::get_bytes;
|
||||||
|
|
@ -286,6 +290,60 @@ pub async fn load_block(block_number: u32) -> Result<Block, String> {
|
||||||
i += body_len;
|
i += body_len;
|
||||||
storage
|
storage
|
||||||
}
|
}
|
||||||
|
STORAGE_I8_TYPE => {
|
||||||
|
let storage = Transaction::StorageI8(
|
||||||
|
StorageI8::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I16_TYPE => {
|
||||||
|
let storage = Transaction::StorageI16(
|
||||||
|
StorageI16::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I32_TYPE => {
|
||||||
|
let storage = Transaction::StorageI32(
|
||||||
|
StorageI32::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I64_TYPE => {
|
||||||
|
let storage = Transaction::StorageI64(
|
||||||
|
StorageI64::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
STORAGE_I128_TYPE => {
|
||||||
|
let storage = Transaction::StorageI128(
|
||||||
|
StorageI128::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
DELETE_KEY_TYPE => {
|
||||||
|
let delete_key = Transaction::DeleteKey(
|
||||||
|
DeleteKey::from_bytes(txtype, body)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
|
i += body_len;
|
||||||
|
delete_key
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(format!("Unsupported transaction type: {txtype}"));
|
return Err(format!("Unsupported transaction type: {txtype}"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::blocks::burn::BurnTransaction;
|
use crate::blocks::burn::BurnTransaction;
|
||||||
use crate::blocks::collateral::CollateralClaimTransaction;
|
use crate::blocks::collateral::CollateralClaimTransaction;
|
||||||
|
use crate::blocks::delete_key::DeleteKey;
|
||||||
use crate::blocks::genesis::GenesisTransaction;
|
use crate::blocks::genesis::GenesisTransaction;
|
||||||
use crate::blocks::issue_token::IssueTokenTransaction;
|
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||||
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
||||||
|
|
@ -9,7 +10,8 @@ use crate::blocks::nft::CreateNftTransaction;
|
||||||
use crate::blocks::rewards::RewardsTransaction;
|
use crate::blocks::rewards::RewardsTransaction;
|
||||||
use crate::blocks::storage_key::StorageKey;
|
use crate::blocks::storage_key::StorageKey;
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
||||||
};
|
};
|
||||||
use crate::blocks::swap::SwapTransaction;
|
use crate::blocks::swap::SwapTransaction;
|
||||||
use crate::blocks::token::CreateTokenTransaction;
|
use crate::blocks::token::CreateTokenTransaction;
|
||||||
|
|
@ -100,6 +102,12 @@ pub fn get_bytes(tx_type: u8) -> usize {
|
||||||
105 => StorageU64::BYTE_LENGTH,
|
105 => StorageU64::BYTE_LENGTH,
|
||||||
106 => StorageU128::BYTE_LENGTH,
|
106 => StorageU128::BYTE_LENGTH,
|
||||||
107 => StorageString::BYTE_LENGTH,
|
107 => StorageString::BYTE_LENGTH,
|
||||||
|
108 => StorageI8::BYTE_LENGTH,
|
||||||
|
109 => StorageI16::BYTE_LENGTH,
|
||||||
|
110 => StorageI32::BYTE_LENGTH,
|
||||||
|
111 => StorageI64::BYTE_LENGTH,
|
||||||
|
112 => StorageI128::BYTE_LENGTH,
|
||||||
|
113 => DeleteKey::BYTE_LENGTH,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,12 @@ async fn miner_earnings_from_transactions(
|
||||||
Transaction::StorageU64(tx) => earnings.add_fee(tx.unsigned_storageu64.txfee)?,
|
Transaction::StorageU64(tx) => earnings.add_fee(tx.unsigned_storageu64.txfee)?,
|
||||||
Transaction::StorageU128(tx) => earnings.add_fee(tx.unsigned_storageu128.txfee)?,
|
Transaction::StorageU128(tx) => earnings.add_fee(tx.unsigned_storageu128.txfee)?,
|
||||||
Transaction::StorageString(tx) => earnings.add_fee(tx.unsigned_storage.txfee)?,
|
Transaction::StorageString(tx) => earnings.add_fee(tx.unsigned_storage.txfee)?,
|
||||||
|
Transaction::StorageI8(tx) => earnings.add_fee(tx.unsigned_storagei8.txfee)?,
|
||||||
|
Transaction::StorageI16(tx) => earnings.add_fee(tx.unsigned_storagei16.txfee)?,
|
||||||
|
Transaction::StorageI32(tx) => earnings.add_fee(tx.unsigned_storagei32.txfee)?,
|
||||||
|
Transaction::StorageI64(tx) => earnings.add_fee(tx.unsigned_storagei64.txfee)?,
|
||||||
|
Transaction::StorageI128(tx) => earnings.add_fee(tx.unsigned_storagei128.txfee)?,
|
||||||
|
Transaction::DeleteKey(tx) => earnings.add_fee(tx.unsigned_deletekey.txfee)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +160,7 @@ async fn miner_earnings_for_block(db: &Db, block_height: u32) -> Result<Vec<u8>,
|
||||||
fn signature_count(transaction_type: u8) -> usize {
|
fn signature_count(transaction_type: u8) -> usize {
|
||||||
match transaction_type {
|
match transaction_type {
|
||||||
6 | 7 => 2,
|
6 | 7 => 2,
|
||||||
2..=5 | 8..=12 | 100..=107 => 1,
|
2..=5 | 8..=12 | 100..=113 => 1,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::blocks::burn::BurnTransaction;
|
use crate::blocks::burn::BurnTransaction;
|
||||||
use crate::blocks::collateral::CollateralClaimTransaction;
|
use crate::blocks::collateral::CollateralClaimTransaction;
|
||||||
|
use crate::blocks::delete_key::DeleteKey;
|
||||||
use crate::blocks::issue_token::IssueTokenTransaction;
|
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||||
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
use crate::blocks::loan_payment::ContractPaymentTransaction;
|
||||||
use crate::blocks::loans::LoanContractTransaction;
|
use crate::blocks::loans::LoanContractTransaction;
|
||||||
|
|
@ -7,15 +8,17 @@ use crate::blocks::marketing::MarketingTransaction;
|
||||||
use crate::blocks::nft::CreateNftTransaction;
|
use crate::blocks::nft::CreateNftTransaction;
|
||||||
use crate::blocks::storage_key::StorageKey;
|
use crate::blocks::storage_key::StorageKey;
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
||||||
};
|
};
|
||||||
use crate::blocks::swap::SwapTransaction;
|
use crate::blocks::swap::SwapTransaction;
|
||||||
use crate::blocks::token::CreateTokenTransaction;
|
use crate::blocks::token::CreateTokenTransaction;
|
||||||
use crate::blocks::transfer::TransferTransaction;
|
use crate::blocks::transfer::TransferTransaction;
|
||||||
use crate::blocks::vanity::VanityAddressTransaction;
|
use crate::blocks::vanity::VanityAddressTransaction;
|
||||||
use crate::common::types::{
|
use crate::common::types::{
|
||||||
BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE,
|
BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE, DELETE_KEY_TYPE,
|
||||||
ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, STORAGE_BOOL_TYPE, STORAGE_KEY_TYPE,
|
ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, STORAGE_BOOL_TYPE, STORAGE_I128_TYPE,
|
||||||
|
STORAGE_I16_TYPE, STORAGE_I32_TYPE, STORAGE_I64_TYPE, STORAGE_I8_TYPE, STORAGE_KEY_TYPE,
|
||||||
STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE,
|
STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE,
|
||||||
STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE,
|
STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE,
|
||||||
};
|
};
|
||||||
|
|
@ -605,6 +608,12 @@ pub async fn save_and_submit(
|
||||||
STORAGE_U64_TYPE => submit_storage_value!(StorageU64, txtype, tx, db, map),
|
STORAGE_U64_TYPE => submit_storage_value!(StorageU64, txtype, tx, db, map),
|
||||||
STORAGE_U128_TYPE => submit_storage_value!(StorageU128, txtype, tx, db, map),
|
STORAGE_U128_TYPE => submit_storage_value!(StorageU128, txtype, tx, db, map),
|
||||||
STORAGE_STRING_TYPE => submit_storage_value!(StorageString, txtype, tx, db, map),
|
STORAGE_STRING_TYPE => submit_storage_value!(StorageString, txtype, tx, db, map),
|
||||||
|
STORAGE_I8_TYPE => submit_storage_value!(StorageI8, txtype, tx, db, map),
|
||||||
|
STORAGE_I16_TYPE => submit_storage_value!(StorageI16, txtype, tx, db, map),
|
||||||
|
STORAGE_I32_TYPE => submit_storage_value!(StorageI32, txtype, tx, db, map),
|
||||||
|
STORAGE_I64_TYPE => submit_storage_value!(StorageI64, txtype, tx, db, map),
|
||||||
|
STORAGE_I128_TYPE => submit_storage_value!(StorageI128, txtype, tx, db, map),
|
||||||
|
DELETE_KEY_TYPE => submit_storage_value!(DeleteKey, txtype, tx, db, map),
|
||||||
_ => {
|
_ => {
|
||||||
let msg = "error: No such transaction type"
|
let msg = "error: No such transaction type"
|
||||||
.to_string()
|
.to_string()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::blocks::burn::{BurnTransaction, UnsignedBurnTransaction};
|
use crate::blocks::burn::{BurnTransaction, UnsignedBurnTransaction};
|
||||||
use crate::blocks::collateral::{CollateralClaimTransaction, UnsignedCollateralClaimTransaction};
|
use crate::blocks::collateral::{CollateralClaimTransaction, UnsignedCollateralClaimTransaction};
|
||||||
|
use crate::blocks::delete_key::{DeleteKey, UnsignedDeleteKey};
|
||||||
use crate::blocks::issue_token::{IssueTokenTransaction, UnsignedIssueTokenTransaction};
|
use crate::blocks::issue_token::{IssueTokenTransaction, UnsignedIssueTokenTransaction};
|
||||||
use crate::blocks::loan_payment::{ContractPaymentTransaction, UnsignedContractPaymentTransaction};
|
use crate::blocks::loan_payment::{ContractPaymentTransaction, UnsignedContractPaymentTransaction};
|
||||||
use crate::blocks::loans::{LoanContractTransaction, UnsignedLoanContractTransaction};
|
use crate::blocks::loans::{LoanContractTransaction, UnsignedLoanContractTransaction};
|
||||||
|
|
@ -7,8 +8,10 @@ use crate::blocks::marketing::{MarketingTransaction, UnsignedMarketingTransactio
|
||||||
use crate::blocks::nft::{CreateNftTransaction, UnsignedCreateNftTransaction};
|
use crate::blocks::nft::{CreateNftTransaction, UnsignedCreateNftTransaction};
|
||||||
use crate::blocks::storage_key::{StorageKey, UnsignedStorageKey};
|
use crate::blocks::storage_key::{StorageKey, UnsignedStorageKey};
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
StorageBool, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
StorageBool, StorageI128, StorageI16, StorageI32, StorageI64, StorageI8, StorageString,
|
||||||
UnsignedStorageBool, UnsignedStorageString, UnsignedStorageU128, UnsignedStorageU16,
|
StorageU128, StorageU16, StorageU32, StorageU64, StorageU8, UnsignedStorageBool,
|
||||||
|
UnsignedStorageI128, UnsignedStorageI16, UnsignedStorageI32, UnsignedStorageI64,
|
||||||
|
UnsignedStorageI8, UnsignedStorageString, UnsignedStorageU128, UnsignedStorageU16,
|
||||||
UnsignedStorageU32, UnsignedStorageU64, UnsignedStorageU8,
|
UnsignedStorageU32, UnsignedStorageU64, UnsignedStorageU8,
|
||||||
};
|
};
|
||||||
use crate::blocks::swap::{SwapTransaction, UnsignedSwapTransaction};
|
use crate::blocks::swap::{SwapTransaction, UnsignedSwapTransaction};
|
||||||
|
|
@ -16,8 +19,9 @@ use crate::blocks::token::{CreateTokenTransaction, UnsignedCreateTokenTransactio
|
||||||
use crate::blocks::transfer::{TransferTransaction, UnsignedTransferTransaction};
|
use crate::blocks::transfer::{TransferTransaction, UnsignedTransferTransaction};
|
||||||
use crate::blocks::vanity::{UnsignedVanityAddressTransaction, VanityAddressTransaction};
|
use crate::blocks::vanity::{UnsignedVanityAddressTransaction, VanityAddressTransaction};
|
||||||
use crate::common::types::{
|
use crate::common::types::{
|
||||||
STORAGE_BOOL_TYPE, STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE,
|
DELETE_KEY_TYPE, STORAGE_BOOL_TYPE, STORAGE_I128_TYPE, STORAGE_I16_TYPE, STORAGE_I32_TYPE,
|
||||||
STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE,
|
STORAGE_I64_TYPE, STORAGE_I8_TYPE, STORAGE_KEY_TYPE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE,
|
||||||
|
STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE,
|
||||||
};
|
};
|
||||||
use crate::records::memory::response_channels::Byte3;
|
use crate::records::memory::response_channels::Byte3;
|
||||||
use crate::rpc::command_maps::RPC_SUBMIT_TRANSACTION;
|
use crate::rpc::command_maps::RPC_SUBMIT_TRANSACTION;
|
||||||
|
|
@ -88,6 +92,28 @@ fn read_transaction_type(transaction: &Value) -> Option<u8> {
|
||||||
.and_then(|value| value.get("txtype"))
|
.and_then(|value| value.get("txtype"))
|
||||||
.and_then(|value| value.as_u64())
|
.and_then(|value| value.as_u64())
|
||||||
})
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
transaction
|
||||||
|
.get("unsigned_deletekey")
|
||||||
|
.and_then(|value| value.get("txtype"))
|
||||||
|
.and_then(|value| value.as_u64())
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
[
|
||||||
|
"unsigned_storagei8",
|
||||||
|
"unsigned_storagei16",
|
||||||
|
"unsigned_storagei32",
|
||||||
|
"unsigned_storagei64",
|
||||||
|
"unsigned_storagei128",
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.find_map(|field| {
|
||||||
|
transaction
|
||||||
|
.get(field)
|
||||||
|
.and_then(|value| value.get("txtype"))
|
||||||
|
.and_then(|value| value.as_u64())
|
||||||
|
})
|
||||||
|
})
|
||||||
.map(|value| value as u8)
|
.map(|value| value as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,6 +128,14 @@ fn read_u128_field(transaction: &Value, field: &str) -> Option<u128> {
|
||||||
value.to_string().parse::<u128>().ok()
|
value.to_string().parse::<u128>().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_i128_field(transaction: &Value, field: &str) -> Option<i128> {
|
||||||
|
let value = transaction.get(field)?;
|
||||||
|
if let Some(value) = value.as_i64() {
|
||||||
|
return Some(value as i128);
|
||||||
|
}
|
||||||
|
value.as_str()?.trim().parse::<i128>().ok()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_transaction_request(
|
pub async fn create_transaction_request(
|
||||||
command_input: String,
|
command_input: String,
|
||||||
hashkey: Byte3,
|
hashkey: Byte3,
|
||||||
|
|
@ -801,6 +835,213 @@ async fn create_transaction_bytes(transaction: &Value) -> Result<Vec<u8>, String
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to serialize storage-string transaction: {e}"))?
|
.map_err(|e| format!("Failed to serialize storage-string transaction: {e}"))?
|
||||||
}
|
}
|
||||||
|
STORAGE_I8_TYPE => {
|
||||||
|
let payload = storage_payload(transaction, "unsigned_storagei8");
|
||||||
|
let unsigned = UnsignedStorageI8 {
|
||||||
|
txtype,
|
||||||
|
time: read_u32_field(payload, "timestamp", "time").ok_or("Missing timestamp.")?,
|
||||||
|
storagekey: payload["storagekey"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage key hash.")?
|
||||||
|
.to_string(),
|
||||||
|
key: payload["key"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage field key.")?
|
||||||
|
.to_string(),
|
||||||
|
value: i8::try_from(read_i128_field(payload, "value").ok_or("Missing i8 value.")?)
|
||||||
|
.map_err(|_| "Invalid i8 value.")?,
|
||||||
|
address: payload["address"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage writer wallet address.")?
|
||||||
|
.to_string(),
|
||||||
|
txfee: payload["txfee"]
|
||||||
|
.as_u64()
|
||||||
|
.ok_or("Missing or invalid txfee.")?,
|
||||||
|
};
|
||||||
|
StorageI8::load(
|
||||||
|
unsigned,
|
||||||
|
transaction["signature"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing transaction signature.")?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to serialize storage-i8 transaction: {e}"))?
|
||||||
|
}
|
||||||
|
STORAGE_I16_TYPE => {
|
||||||
|
let payload = storage_payload(transaction, "unsigned_storagei16");
|
||||||
|
let unsigned = UnsignedStorageI16 {
|
||||||
|
txtype,
|
||||||
|
time: read_u32_field(payload, "timestamp", "time").ok_or("Missing timestamp.")?,
|
||||||
|
storagekey: payload["storagekey"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage key hash.")?
|
||||||
|
.to_string(),
|
||||||
|
key: payload["key"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage field key.")?
|
||||||
|
.to_string(),
|
||||||
|
value: i16::try_from(
|
||||||
|
read_i128_field(payload, "value").ok_or("Missing i16 value.")?,
|
||||||
|
)
|
||||||
|
.map_err(|_| "Invalid i16 value.")?,
|
||||||
|
address: payload["address"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage writer wallet address.")?
|
||||||
|
.to_string(),
|
||||||
|
txfee: payload["txfee"]
|
||||||
|
.as_u64()
|
||||||
|
.ok_or("Missing or invalid txfee.")?,
|
||||||
|
};
|
||||||
|
StorageI16::load(
|
||||||
|
unsigned,
|
||||||
|
transaction["signature"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing transaction signature.")?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to serialize storage-i16 transaction: {e}"))?
|
||||||
|
}
|
||||||
|
STORAGE_I32_TYPE => {
|
||||||
|
let payload = storage_payload(transaction, "unsigned_storagei32");
|
||||||
|
let unsigned = UnsignedStorageI32 {
|
||||||
|
txtype,
|
||||||
|
time: read_u32_field(payload, "timestamp", "time").ok_or("Missing timestamp.")?,
|
||||||
|
storagekey: payload["storagekey"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage key hash.")?
|
||||||
|
.to_string(),
|
||||||
|
key: payload["key"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage field key.")?
|
||||||
|
.to_string(),
|
||||||
|
value: i32::try_from(
|
||||||
|
read_i128_field(payload, "value").ok_or("Missing i32 value.")?,
|
||||||
|
)
|
||||||
|
.map_err(|_| "Invalid i32 value.")?,
|
||||||
|
address: payload["address"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage writer wallet address.")?
|
||||||
|
.to_string(),
|
||||||
|
txfee: payload["txfee"]
|
||||||
|
.as_u64()
|
||||||
|
.ok_or("Missing or invalid txfee.")?,
|
||||||
|
};
|
||||||
|
StorageI32::load(
|
||||||
|
unsigned,
|
||||||
|
transaction["signature"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing transaction signature.")?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to serialize storage-i32 transaction: {e}"))?
|
||||||
|
}
|
||||||
|
STORAGE_I64_TYPE => {
|
||||||
|
let payload = storage_payload(transaction, "unsigned_storagei64");
|
||||||
|
let unsigned = UnsignedStorageI64 {
|
||||||
|
txtype,
|
||||||
|
time: read_u32_field(payload, "timestamp", "time").ok_or("Missing timestamp.")?,
|
||||||
|
storagekey: payload["storagekey"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage key hash.")?
|
||||||
|
.to_string(),
|
||||||
|
key: payload["key"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage field key.")?
|
||||||
|
.to_string(),
|
||||||
|
value: i64::try_from(
|
||||||
|
read_i128_field(payload, "value").ok_or("Missing i64 value.")?,
|
||||||
|
)
|
||||||
|
.map_err(|_| "Invalid i64 value.")?,
|
||||||
|
address: payload["address"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage writer wallet address.")?
|
||||||
|
.to_string(),
|
||||||
|
txfee: payload["txfee"]
|
||||||
|
.as_u64()
|
||||||
|
.ok_or("Missing or invalid txfee.")?,
|
||||||
|
};
|
||||||
|
StorageI64::load(
|
||||||
|
unsigned,
|
||||||
|
transaction["signature"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing transaction signature.")?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to serialize storage-i64 transaction: {e}"))?
|
||||||
|
}
|
||||||
|
STORAGE_I128_TYPE => {
|
||||||
|
let payload = storage_payload(transaction, "unsigned_storagei128");
|
||||||
|
let unsigned = UnsignedStorageI128 {
|
||||||
|
txtype,
|
||||||
|
time: read_u32_field(payload, "timestamp", "time").ok_or("Missing timestamp.")?,
|
||||||
|
storagekey: payload["storagekey"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage key hash.")?
|
||||||
|
.to_string(),
|
||||||
|
key: payload["key"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage field key.")?
|
||||||
|
.to_string(),
|
||||||
|
value: read_i128_field(payload, "value").ok_or("Missing i128 value.")?,
|
||||||
|
address: payload["address"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage writer wallet address.")?
|
||||||
|
.to_string(),
|
||||||
|
txfee: payload["txfee"]
|
||||||
|
.as_u64()
|
||||||
|
.ok_or("Missing or invalid txfee.")?,
|
||||||
|
};
|
||||||
|
StorageI128::load(
|
||||||
|
unsigned,
|
||||||
|
transaction["signature"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing transaction signature.")?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to serialize storage-i128 transaction: {e}"))?
|
||||||
|
}
|
||||||
|
DELETE_KEY_TYPE => {
|
||||||
|
let payload = storage_payload(transaction, "unsigned_deletekey");
|
||||||
|
let unsigned = UnsignedDeleteKey {
|
||||||
|
txtype,
|
||||||
|
time: read_u32_field(payload, "timestamp", "time").ok_or("Missing timestamp.")?,
|
||||||
|
storagekey: payload["storagekey"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage key hash.")?
|
||||||
|
.to_string(),
|
||||||
|
key: payload["key"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage field key.")?
|
||||||
|
.to_string(),
|
||||||
|
address: payload["address"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing storage owner wallet address.")?
|
||||||
|
.to_string(),
|
||||||
|
txfee: payload["txfee"]
|
||||||
|
.as_u64()
|
||||||
|
.ok_or("Missing or invalid txfee.")?,
|
||||||
|
};
|
||||||
|
DeleteKey::load(
|
||||||
|
unsigned,
|
||||||
|
transaction["signature"]
|
||||||
|
.as_str()
|
||||||
|
.ok_or("Missing transaction signature.")?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.to_bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to serialize delete-key transaction: {e}"))?
|
||||||
|
}
|
||||||
_ => return Err("No such transaction type".to_string()),
|
_ => return Err("No such transaction type".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -569,6 +569,97 @@ async fn transaction_balance_view(
|
||||||
check_saved_txid: true,
|
check_saved_txid: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Transaction::StorageI8(tx) => {
|
||||||
|
let storage = &tx.unsigned_storagei8;
|
||||||
|
let mut debits = Vec::new();
|
||||||
|
add_debit(
|
||||||
|
&mut debits,
|
||||||
|
&storage.address,
|
||||||
|
BASECOIN.clone(),
|
||||||
|
storage.txfee,
|
||||||
|
);
|
||||||
|
Ok(TransactionBalanceView {
|
||||||
|
hash: storage.hash().await,
|
||||||
|
signatures: vec![tx.signature.clone()],
|
||||||
|
debits,
|
||||||
|
check_saved_txid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Transaction::StorageI16(tx) => {
|
||||||
|
let storage = &tx.unsigned_storagei16;
|
||||||
|
let mut debits = Vec::new();
|
||||||
|
add_debit(
|
||||||
|
&mut debits,
|
||||||
|
&storage.address,
|
||||||
|
BASECOIN.clone(),
|
||||||
|
storage.txfee,
|
||||||
|
);
|
||||||
|
Ok(TransactionBalanceView {
|
||||||
|
hash: storage.hash().await,
|
||||||
|
signatures: vec![tx.signature.clone()],
|
||||||
|
debits,
|
||||||
|
check_saved_txid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Transaction::StorageI32(tx) => {
|
||||||
|
let storage = &tx.unsigned_storagei32;
|
||||||
|
let mut debits = Vec::new();
|
||||||
|
add_debit(
|
||||||
|
&mut debits,
|
||||||
|
&storage.address,
|
||||||
|
BASECOIN.clone(),
|
||||||
|
storage.txfee,
|
||||||
|
);
|
||||||
|
Ok(TransactionBalanceView {
|
||||||
|
hash: storage.hash().await,
|
||||||
|
signatures: vec![tx.signature.clone()],
|
||||||
|
debits,
|
||||||
|
check_saved_txid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Transaction::StorageI64(tx) => {
|
||||||
|
let storage = &tx.unsigned_storagei64;
|
||||||
|
let mut debits = Vec::new();
|
||||||
|
add_debit(
|
||||||
|
&mut debits,
|
||||||
|
&storage.address,
|
||||||
|
BASECOIN.clone(),
|
||||||
|
storage.txfee,
|
||||||
|
);
|
||||||
|
Ok(TransactionBalanceView {
|
||||||
|
hash: storage.hash().await,
|
||||||
|
signatures: vec![tx.signature.clone()],
|
||||||
|
debits,
|
||||||
|
check_saved_txid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Transaction::StorageI128(tx) => {
|
||||||
|
let storage = &tx.unsigned_storagei128;
|
||||||
|
let mut debits = Vec::new();
|
||||||
|
add_debit(
|
||||||
|
&mut debits,
|
||||||
|
&storage.address,
|
||||||
|
BASECOIN.clone(),
|
||||||
|
storage.txfee,
|
||||||
|
);
|
||||||
|
Ok(TransactionBalanceView {
|
||||||
|
hash: storage.hash().await,
|
||||||
|
signatures: vec![tx.signature.clone()],
|
||||||
|
debits,
|
||||||
|
check_saved_txid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Transaction::DeleteKey(tx) => {
|
||||||
|
let delete = &tx.unsigned_deletekey;
|
||||||
|
let mut debits = Vec::new();
|
||||||
|
add_debit(&mut debits, &delete.address, BASECOIN.clone(), delete.txfee);
|
||||||
|
Ok(TransactionBalanceView {
|
||||||
|
hash: delete.hash().await,
|
||||||
|
signatures: vec![tx.signature.clone()],
|
||||||
|
debits,
|
||||||
|
check_saved_txid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ pub mod verify_burn;
|
||||||
pub mod verify_collateral;
|
pub mod verify_collateral;
|
||||||
pub mod verify_create_nft;
|
pub mod verify_create_nft;
|
||||||
pub mod verify_create_token;
|
pub mod verify_create_token;
|
||||||
|
pub mod verify_delete_key;
|
||||||
pub mod verify_genesis;
|
pub mod verify_genesis;
|
||||||
pub mod verify_issue_token;
|
pub mod verify_issue_token;
|
||||||
pub mod verify_lender;
|
pub mod verify_lender;
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,84 @@ async fn verify_transaction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Transaction::StorageI8(storage_tx) = &transaction {
|
||||||
|
match storage_tx.verify(db).await {
|
||||||
|
Ok(value) => {
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"Validation failed for storage i8 transaction: {err}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Transaction::StorageI16(storage_tx) = &transaction {
|
||||||
|
match storage_tx.verify(db).await {
|
||||||
|
Ok(value) => {
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"Validation failed for storage i16 transaction: {err}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Transaction::StorageI32(storage_tx) = &transaction {
|
||||||
|
match storage_tx.verify(db).await {
|
||||||
|
Ok(value) => {
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"Validation failed for storage i32 transaction: {err}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Transaction::StorageI64(storage_tx) = &transaction {
|
||||||
|
match storage_tx.verify(db).await {
|
||||||
|
Ok(value) => {
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"Validation failed for storage i64 transaction: {err}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Transaction::StorageI128(storage_tx) = &transaction {
|
||||||
|
match storage_tx.verify(db).await {
|
||||||
|
Ok(value) => {
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"Validation failed for storage i128 transaction: {err}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Transaction::DeleteKey(delete_key_tx) = &transaction {
|
||||||
|
match delete_key_tx.verify(db).await {
|
||||||
|
Ok(value) => {
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"Validation failed for delete-key transaction: {err}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(
|
Err(
|
||||||
"Validation failed: unsupported transaction variant reached verification dispatch."
|
"Validation failed: unsupported transaction variant reached verification dispatch."
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
use crate::blocks::delete_key::{delete_record_keys, DeleteKey};
|
||||||
|
use crate::blocks::storage_values::{STORAGE_KEY_HASH_BYTES, STORAGE_VALUE_KEY_BYTES};
|
||||||
|
use crate::common::types::{DELETE_KEY_TYPE, STORAGE_KEY_INDEX_TREE, STORAGE_VALUE_FEE};
|
||||||
|
use crate::records::memory::mempool::BASECOIN;
|
||||||
|
use crate::records::wallet_registry::{
|
||||||
|
require_canonical_registered_short_address, resolve_pubkey_from_short_address,
|
||||||
|
};
|
||||||
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
|
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
||||||
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
|
use crate::wallets::structures::Wallet;
|
||||||
|
use crate::{decode, encode, sled::Db};
|
||||||
|
|
||||||
|
impl DeleteKey {
|
||||||
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
|
let delete = &self.unsigned_deletekey;
|
||||||
|
let hash = delete.hash().await;
|
||||||
|
|
||||||
|
// Existing mempool entries short-circuit before the storage-state checks.
|
||||||
|
if memcheck(&self.signature, &hash).await {
|
||||||
|
return Ok(self.signature.clone());
|
||||||
|
}
|
||||||
|
if delete.txtype != DELETE_KEY_TYPE {
|
||||||
|
return Err("Delete-key transaction type is invalid.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The namespace must be a previously confirmed StorageKey transaction.
|
||||||
|
let storagekey = decode(&delete.storagekey)
|
||||||
|
.map_err(|err| format!("Delete-key storage hash is invalid: {err}"))?;
|
||||||
|
if storagekey.len() != STORAGE_KEY_HASH_BYTES {
|
||||||
|
return Err("Delete-key storage hash length is invalid.".to_string());
|
||||||
|
}
|
||||||
|
if delete.key.as_bytes().len() != STORAGE_VALUE_KEY_BYTES {
|
||||||
|
return Err("Delete-key field key length is invalid.".to_string());
|
||||||
|
}
|
||||||
|
let storage_index = db
|
||||||
|
.open_tree(STORAGE_KEY_INDEX_TREE)
|
||||||
|
.map_err(|err| format!("Could not open storage key index: {err}"))?;
|
||||||
|
if !storage_index
|
||||||
|
.contains_key(&storagekey)
|
||||||
|
.map_err(|err| format!("Could not check storage key index: {err}"))?
|
||||||
|
{
|
||||||
|
return Err("Delete-key storage key does not exist.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only the registered owner of this address-scoped data can delete it.
|
||||||
|
if !Wallet::short_address_validation(&delete.address) {
|
||||||
|
return Err("Delete-key wallet address is invalid.".to_string());
|
||||||
|
}
|
||||||
|
require_canonical_registered_short_address(
|
||||||
|
db,
|
||||||
|
&delete.address,
|
||||||
|
"Delete-key wallet address",
|
||||||
|
)?;
|
||||||
|
let public_key = resolve_pubkey_from_short_address(db, &delete.address)
|
||||||
|
.map_err(|_| "Delete-key wallet address is not registered.".to_string())?
|
||||||
|
.ok_or_else(|| "Delete-key wallet address is not registered.".to_string())?;
|
||||||
|
if !Wallet::verify_transaction_with_public_key(&hash, &self.signature, &encode(public_key))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Err("Invalid signature for the Delete Key Transaction.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if delete.txfee < STORAGE_VALUE_FEE {
|
||||||
|
return Err(format!(
|
||||||
|
"Delete-key transaction fee is below the minimum required fee of {STORAGE_VALUE_FEE}."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if !balance_checkup(db, 0, delete.txfee, BASECOIN.clone(), &delete.address).await {
|
||||||
|
return Err("Insuficient funds for this Delete Key Transaction!".to_string());
|
||||||
|
}
|
||||||
|
if !db_hex_verification(db, "txid", &hash).await {
|
||||||
|
return Err("This transaction already exists.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject no-op deletes. Base keys inspect the scalar and all 20 string chunks;
|
||||||
|
// explicit _00 through _19 keys inspect only that exact chunk.
|
||||||
|
let tree = db
|
||||||
|
.open_tree(&storagekey)
|
||||||
|
.map_err(|err| format!("Could not open storage tree: {err}"))?;
|
||||||
|
let targets = delete_record_keys(&delete.address, &delete.key)?;
|
||||||
|
let mut found = false;
|
||||||
|
for target in targets {
|
||||||
|
if tree
|
||||||
|
.contains_key(target)
|
||||||
|
.map_err(|err| format!("Could not inspect storage record: {err}"))?
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return Err("Delete-key target does not exist.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::blocks::storage_values::{
|
use crate::blocks::storage_values::{
|
||||||
storage_string_record_key, StorageBool, StorageString, StorageU128, StorageU16, StorageU32,
|
storage_string_record_key, StorageBool, StorageI128, StorageI16, StorageI32, StorageI64,
|
||||||
StorageU64, StorageU8, StorageValueTransaction, STORAGE_KEY_HASH_BYTES,
|
StorageI8, StorageString, StorageU128, StorageU16, StorageU32, StorageU64, StorageU8,
|
||||||
STORAGE_STRING_VALUE_BYTES, STORAGE_VALUE_KEY_BYTES,
|
StorageValueTransaction, STORAGE_KEY_HASH_BYTES, STORAGE_STRING_VALUE_BYTES,
|
||||||
|
STORAGE_VALUE_KEY_BYTES,
|
||||||
};
|
};
|
||||||
use crate::common::types::{
|
use crate::common::types::{
|
||||||
STORAGE_BOOL_TYPE, STORAGE_KEY_INDEX_TREE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE,
|
STORAGE_BOOL_TYPE, STORAGE_I128_TYPE, STORAGE_I16_TYPE, STORAGE_I32_TYPE, STORAGE_I64_TYPE,
|
||||||
|
STORAGE_I8_TYPE, STORAGE_KEY_INDEX_TREE, STORAGE_STRING_TYPE, STORAGE_U128_TYPE,
|
||||||
STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE, STORAGE_VALUE_FEE,
|
STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE, STORAGE_U8_TYPE, STORAGE_VALUE_FEE,
|
||||||
};
|
};
|
||||||
use crate::decode;
|
use crate::decode;
|
||||||
|
|
@ -151,6 +153,36 @@ impl StorageU128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StorageI8 {
|
||||||
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
|
verify_storage_value(self, db, STORAGE_I8_TYPE, "Storage I8").await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StorageI16 {
|
||||||
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
|
verify_storage_value(self, db, STORAGE_I16_TYPE, "Storage I16").await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StorageI32 {
|
||||||
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
|
verify_storage_value(self, db, STORAGE_I32_TYPE, "Storage I32").await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StorageI64 {
|
||||||
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
|
verify_storage_value(self, db, STORAGE_I64_TYPE, "Storage I64").await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StorageI128 {
|
||||||
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
|
verify_storage_value(self, db, STORAGE_I128_TYPE, "Storage I128").await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl StorageString {
|
impl StorageString {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
// String storage has extra chain-linking rules before it can use
|
// String storage has extra chain-linking rules before it can use
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue