diff --git a/vm/src/tx_execution/system_sc/system_sc_issue.rs b/vm/src/tx_execution/system_sc/system_sc_issue.rs index 553b4c1054..666d44678f 100644 --- a/vm/src/tx_execution/system_sc/system_sc_issue.rs +++ b/vm/src/tx_execution/system_sc/system_sc_issue.rs @@ -2,7 +2,7 @@ use num_bigint::BigUint; use crate::{ crypto_functions::keccak256, - tx_mock::{TxContext, TxResult}, + tx_mock::{TxCache, TxContext, TxInput, TxResult}, types::top_decode_u64, }; @@ -22,13 +22,21 @@ pub fn issue(tx_context: TxContext) -> (TxContext, TxResult) { let _decimals = top_decode_u64(tx_input.args[3].clone().as_ref()) as u32; let mut new_token_identifiers = tx_cache.get_new_token_identifiers(); - let token_identifier = if let Some(ti) = new_token_identifiers.pop_front() { - println!("\n\ntoken_identifier: {}\n\n", ti); + + let token_identifier = if let Some((i, ti)) = + first_token_identifier_with_ticker(&new_token_identifiers, &ticker) + { + new_token_identifiers.remove(i); ti.into_bytes() } else { generate_token_identifier_from_ticker(tx_input, tx_cache, &ticker) }; + println!( + "\n\ngenerated new token_identifier: {}\n\n", + std::str::from_utf8(&token_identifier).unwrap() + ); + tx_cache.with_account_mut(&tx_input.from, |account| { account.esdt.issue_token(&token_identifier); }); @@ -42,12 +50,12 @@ pub fn issue(tx_context: TxContext) -> (TxContext, TxResult) { (tx_context, tx_result) } -/// Issues a semi-fungible token. +/// Issues a new semi-fungible token. pub fn issue_semi_fungible(tx_context: TxContext) -> (TxContext, TxResult) { issue_non_fungible(tx_context) } -/// Issues a non-fungible token. +/// Issues a new non-fungible token. pub fn issue_non_fungible(tx_context: TxContext) -> (TxContext, TxResult) { let tx_input = tx_context.input_ref(); let tx_cache = tx_context.blockchain_cache(); @@ -61,8 +69,11 @@ pub fn issue_non_fungible(tx_context: TxContext) -> (TxContext, TxResult) { let ticker = tx_input.args[1].clone(); let mut new_token_identifiers = tx_cache.get_new_token_identifiers(); - let token_identifier = if let Some(ti) = new_token_identifiers.pop_front() { - println!("\n\ntoken_identifier: {}\n\n", ti); + + let token_identifier = if let Some((i, ti)) = + first_token_identifier_with_ticker(&new_token_identifiers, &ticker) + { + new_token_identifiers.remove(i); ti.into_bytes() } else { generate_token_identifier_from_ticker(tx_input, tx_cache, &ticker) @@ -81,9 +92,27 @@ pub fn issue_non_fungible(tx_context: TxContext) -> (TxContext, TxResult) { (tx_context, tx_result) } +fn first_token_identifier_with_ticker( + token_identifiers: &Vec, + ticker: &[u8], +) -> Option<(usize, String)> { + let extract_ticker = + |ti: &String| -> String { ti.split("-").map(|x| x.to_string()).next().unwrap() }; + + let position = token_identifiers + .iter() + .position(|x| extract_ticker(x).as_bytes() == ticker); + + if let Some(i) = position { + Some((i, token_identifiers[i].clone())) + } else { + None + } +} + fn generate_token_identifier_from_ticker( - tx_input: &crate::tx_mock::TxInput, - tx_cache: &crate::tx_mock::TxCache, + tx_input: &TxInput, + tx_cache: &TxCache, ticker: &[u8], ) -> Vec { let new_random_base = [ @@ -104,10 +133,36 @@ fn generate_token_identifier_from_ticker( hex::encode(new_random_for_ticker).as_bytes(), ] .concat(); - println!( - "\n\ngenerated new token_identifier: {}\n\n", - std::str::from_utf8(&token_identifier).unwrap() - ); token_identifier } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_first_token_identifier_with_ticker_ok() { + let ticker = String::from("BBBB").into_bytes(); + let new_token_indetifiers = vec![ + "AAAA-0123".to_string(), + "BBBB-4567".to_string(), + "BBBB-0123".to_string(), + "CCCC-4567".to_string(), + ]; + + let ti = first_token_identifier_with_ticker(&new_token_indetifiers, &ticker); + let expected = b"BBBB-4567".as_slice(); + assert_eq!(expected, ti.unwrap().1.into_bytes()); + } + + #[test] + fn test_first_token_identifier_with_ticker_is_none() { + let ticker = String::from("BBBB").into_bytes(); + let new_token_indetifiers = vec!["AAAA-0123".to_string()]; + + let i = first_token_identifier_with_ticker(&new_token_indetifiers, &ticker); + let expected = None; + assert_eq!(expected, i); + } +} diff --git a/vm/src/tx_mock/tx_cache.rs b/vm/src/tx_mock/tx_cache.rs index c32bfbe106..c188a78e33 100644 --- a/vm/src/tx_mock/tx_cache.rs +++ b/vm/src/tx_mock/tx_cache.rs @@ -1,6 +1,6 @@ use std::{ cell::{Ref, RefCell}, - collections::{HashMap, VecDeque}, + collections::HashMap, fmt, rc::Rc, }; @@ -16,7 +16,7 @@ use super::TxCacheSource; pub struct TxCache { source_ref: Rc, pub(super) accounts: RefCell>, - pub(super) new_token_identifiers: RefCell>>, + pub(super) new_token_identifiers: RefCell>>, } impl fmt::Debug for TxCache { @@ -99,11 +99,11 @@ impl TxCache { }) } - pub fn get_new_token_identifiers(&self) -> VecDeque { + pub fn get_new_token_identifiers(&self) -> Vec { self.blockchain_ref().get_new_token_identifiers() } - pub fn set_new_token_identifiers(&self, token_identifiers: VecDeque) { + pub fn set_new_token_identifiers(&self, token_identifiers: Vec) { *self.new_token_identifiers.borrow_mut() = Some(token_identifiers); } @@ -123,7 +123,7 @@ impl TxCache { pub struct BlockchainUpdate { accounts: HashMap, - new_token_identifiers: Option>, + new_token_identifiers: Option>, } impl BlockchainUpdate { diff --git a/vm/src/world_mock/blockchain_mock.rs b/vm/src/world_mock/blockchain_mock.rs index d2d6f589f5..b6288953ac 100644 --- a/vm/src/world_mock/blockchain_mock.rs +++ b/vm/src/world_mock/blockchain_mock.rs @@ -6,11 +6,7 @@ use crate::{ use multiversx_chain_vm_executor::Executor; use num_bigint::BigUint; use num_traits::Zero; -use std::{ - collections::{HashMap, VecDeque}, - fmt::Debug, - rc::Rc, -}; +use std::{collections::HashMap, fmt::Debug, rc::Rc}; use super::{AccountData, BlockInfo, FailingExecutor}; @@ -20,7 +16,7 @@ pub struct BlockchainMock { pub accounts: HashMap, pub builtin_functions: Rc, pub new_addresses: HashMap<(VMAddress, u64), VMAddress>, - pub new_token_identifiers: VecDeque, + pub new_token_identifiers: Vec, pub previous_block_info: BlockInfo, pub current_block_info: BlockInfo, pub executor: Box, @@ -32,7 +28,7 @@ impl BlockchainMock { accounts: HashMap::new(), builtin_functions: Rc::new(init_builtin_functions()), new_addresses: HashMap::new(), - new_token_identifiers: VecDeque::new(), + new_token_identifiers: Vec::new(), previous_block_info: BlockInfo::new(), current_block_info: BlockInfo::new(), executor, @@ -40,14 +36,14 @@ impl BlockchainMock { } pub fn put_new_token_identifier(&mut self, token_identifier: String) { - self.new_token_identifiers.push_back(token_identifier) + self.new_token_identifiers.push(token_identifier) } - pub fn get_new_token_identifiers(&self) -> VecDeque { + pub fn get_new_token_identifiers(&self) -> Vec { self.new_token_identifiers.clone() } - pub fn update_new_token_identifiers(&mut self, token_identifiers: VecDeque) { + pub fn update_new_token_identifiers(&mut self, token_identifiers: Vec) { self.new_token_identifiers = token_identifiers; }