chaintester/
client.rs

1use std::fmt;
2use std::panic;
3
4use std::{fs};
5use std::{thread, time::Duration};
6use std::ops::{Deref, DerefMut};
7use std::collections::{HashMap};
8use serde_json::{Value};
9
10use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol};
11use thrift::transport::{
12    ReadHalf, TBufferedReadTransport, TBufferedWriteTransport, TIoChannel, TTcpChannel, WriteHalf,
13};
14
15use crate::interfaces::{
16    IPCChainTesterSyncClient,
17    TIPCChainTesterSyncClient,
18    ApplySyncClient,
19    Action,
20    ActionArguments,
21};
22
23type ClientInputProtocol = TBinaryInputProtocol<TBufferedReadTransport<ReadHalf<TTcpChannel>>>;
24type ClientOutputProtocol = TBinaryOutputProtocol<TBufferedWriteTransport<WriteHalf<TTcpChannel>>>;
25
26
27use std::convert::{From, Into, TryInto};
28
29use lazy_static::lazy_static; // 1.4.0
30use std::sync::{
31    Mutex,
32    MutexGuard
33};
34
35
36pub struct ChainTesterError {
37    pub json: Option<Value>,
38    pub error_string: Option<String>,
39}
40
41pub enum JsonKeyType {
42    ArrayIndex(usize),
43    MapKey(String)
44}
45
46impl From<usize> for JsonKeyType {
47    fn from(value: usize) -> Self {
48        JsonKeyType::ArrayIndex(value)
49    }
50}
51
52impl From<String> for JsonKeyType {
53    fn from(value: String) -> Self {
54        JsonKeyType::MapKey(value)
55    }
56}
57
58impl ChainTesterError {
59    pub fn get_err(&self) -> Option<String> {
60        let value = &self.json.as_ref().unwrap()["except"]["stack"][0]["data"]["s"];
61        if let Value::String(s) = value {
62            return Some(s.clone())
63        }
64        return None;
65    }
66
67    pub fn check_err(&self, err: &str) {
68        let err2 = &self.get_err().unwrap() ;
69        if err2 != err {
70            panic!("invalid error, expect {}, got {}", err, err2);
71        }
72    }
73}
74
75impl fmt::Display for ChainTesterError {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        if let Some(ref value) = self.json {
78            write!(f, "{}", serde_json::to_string_pretty(value).unwrap())
79        } else {
80            if let Some(ref err) = self.error_string {
81                write!(f, "{}", err)
82            } else {
83                write!(f, "{}", "Unknown error")
84            }
85        }
86    }
87}
88
89impl fmt::Debug for ChainTesterError {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        if let Some(ref value) = self.json {
92            write!(f, "{}", serde_json::to_string_pretty(&value).unwrap())
93        } else {
94            if let Some(ref err) = self.error_string {
95                write!(f, "{}", err)
96            } else {
97                write!(f, "{}", "Unknown error")
98            }
99        }
100    }
101}
102
103pub struct TransactionReturn {
104    pub value: Value
105}
106
107impl fmt::Display for TransactionReturn {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        write!(f, "{}", serde_json::to_string_pretty(&self.value).unwrap())
110    }
111}
112
113impl fmt::Debug for TransactionReturn {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        write!(f, "{}", serde_json::to_string_pretty(&self.value).unwrap())
116    }
117}
118
119pub type Result<T> = core::result::Result<T, ChainTesterError>;
120
121pub struct GetTableRowsPrams<'a> {
122    pub json: bool,
123    pub code: &'a str,
124    pub scope: &'a str,
125    pub table: &'a str,
126    pub lower_bound: &'a str,
127    pub upper_bound: &'a str,
128    pub limit: i64,
129    pub key_type: &'a str,
130    pub index_position: &'a str,
131    pub reverse: bool,
132    pub show_payer: bool,
133}
134
135impl<'a> Default for GetTableRowsPrams<'a> {
136    fn default() -> Self {
137        Self {
138            json: true,
139            code: "",
140            scope: "",
141            table: "",
142            lower_bound: "",
143            upper_bound: "",
144            limit: 10,
145            key_type: "",
146            index_position: "",
147            reverse: false,
148            show_payer: false
149        }
150    }
151}
152
153pub struct VMAPIClient {
154    vm_api_client: Option<ApplySyncClient<ClientInputProtocol, ClientOutputProtocol>>,
155    in_apply: bool,
156}
157
158pub struct ChainTesterClient {
159    client: Option<IPCChainTesterSyncClient<ClientInputProtocol, ClientOutputProtocol>>,
160}
161
162lazy_static! {
163    static ref VM_API_CLIENT: Mutex<VMAPIClient> = Mutex::new(VMAPIClient::new());
164}
165
166lazy_static! {
167    static ref CHAIN_TESTER_CLIENT: Mutex<ChainTesterClient> = Mutex::new(ChainTesterClient::new());
168}
169
170lazy_static! {
171    static ref TEST_MUTEX: Mutex<i32> = Mutex::new(0);
172}
173
174type FnApply = fn(u64, u64, u64);
175
176lazy_static! {
177    static ref CHAIN_TESTER_APPLYS: Mutex<HashMap<i32, HashMap<String, FnApply>>> = Mutex::new(HashMap::new());
178}
179
180pub fn get_test_mutex() -> MutexGuard<'static, i32> {
181    let ret = TEST_MUTEX.lock().unwrap();
182    return ret;
183}
184
185pub fn get_apply_map_mutex() -> MutexGuard<'static, HashMap<i32, HashMap<String, FnApply>>> {
186    let ret = CHAIN_TESTER_APPLYS.lock().unwrap();
187    return ret;
188}
189
190pub struct GlobalVariables {
191    pub current_test_case: String,
192    pub debug_mode: bool,
193}
194
195impl GlobalVariables {
196    pub fn new() -> Self {
197        GlobalVariables{current_test_case: "".into(), debug_mode: false}
198    }
199
200    pub fn get_current_test_case(&self) -> String {
201        return self.current_test_case.clone();
202    }
203
204    pub fn set_current_test_case(&mut self, test_case: &str) {
205        self.current_test_case = test_case.into();
206    }
207
208    pub fn set_debug_mode(&mut self, enable: bool) {
209        self.debug_mode = enable;
210    }
211
212    pub fn get_debug_mode(&self) -> bool {
213        return self.debug_mode;
214    }
215}
216
217lazy_static! {
218    static ref GLOBAL_VARIABLES: Mutex<GlobalVariables> = Mutex::new(GlobalVariables::new());
219}
220
221pub fn get_globals() -> MutexGuard<'static, GlobalVariables> {
222    return GLOBAL_VARIABLES.lock().unwrap();
223}
224
225pub fn init_vm_api_client() {
226    let mut ret = VM_API_CLIENT.lock().unwrap();
227    if ret.vm_api_client.is_none() {
228        ret.init();
229    }
230}
231
232pub fn get_vm_api_client() -> MutexGuard<'static, VMAPIClient> {
233    let mut ret = VM_API_CLIENT.lock().unwrap();
234    if ret.vm_api_client.is_none() {
235        ret.init();
236    }
237    return ret;
238}
239
240pub fn close_vm_api_client() {
241    let mut ret = VM_API_CLIENT.lock().unwrap();
242    ret.close();
243}
244
245impl VMAPIClient {
246    fn new() -> Self {
247        VMAPIClient{vm_api_client: None, in_apply: false}
248    }
249
250    pub fn init(&mut self) {
251        if self.vm_api_client.is_none() {
252            let host = crate::get_debugger_config().vm_api_server_address.clone();
253            let port = crate::get_debugger_config().vm_api_server_port;
254            let client = new_vm_api_client(&host, port).unwrap();
255            self.vm_api_client = Some(client);
256        }
257    }
258
259    pub fn set_in_apply(&mut self, in_apply: bool) {
260        self.in_apply = in_apply;
261    }
262
263    pub fn is_in_apply(&mut self) -> bool {
264        return self.in_apply;
265    }
266
267    pub fn close(&mut self) {
268        if self.vm_api_client.is_some() {
269            self.vm_api_client = None;
270        }
271    }
272
273    // pub fn client(&mut self) -> &mut ApplySyncClient<ClientInputProtocol, ClientOutputProtocol> {
274    //     self.vm_api_client.as_mut().unwrap()
275    // }
276}
277
278impl Deref for VMAPIClient {
279    type Target = ApplySyncClient<ClientInputProtocol, ClientOutputProtocol>;
280
281    fn deref(&self) -> &ApplySyncClient<ClientInputProtocol, ClientOutputProtocol>
282    {
283        self.vm_api_client.as_ref().unwrap()
284    }
285}
286
287impl DerefMut for VMAPIClient {
288    fn deref_mut(&mut self) -> &mut Self::Target {
289        if !self.is_in_apply() {
290            panic!("error: vm api function has been called out of apply context!");
291        }
292        let client = self.vm_api_client.as_mut().unwrap();
293        return client;
294    }
295}
296// 
297
298impl ChainTesterClient {
299    fn new() -> Self {
300        // better_panic::install();
301        ChainTesterClient{client: None}
302    }
303
304    fn init(&mut self) {
305        if self.client.is_some() {
306            return;
307        }
308
309        let host = crate::get_debugger_config().debugger_server_address.clone();
310        let port = crate::get_debugger_config().debugger_server_port;
311
312        let mut c = TTcpChannel::new();
313    
314        // open the underlying TCP stream
315        println!("connecting to debugger server on {}:{}", host, port);
316        c.open(&format!("{}:{}", host, port)).unwrap();    
317        println!("debugger server connected");
318        
319        // clone the TCP channel into two halves, one which
320        // we'll use for reading, the other for writing
321        let (i_chan, o_chan) = c.split().unwrap();
322    
323        // wrap the raw sockets (slow) with a buffered transport of some kind
324        let i_tran = TBufferedReadTransport::new(i_chan);
325        let o_tran = TBufferedWriteTransport::new(o_chan);
326    
327        // now create the protocol implementations
328        let i_prot = TBinaryInputProtocol::new(i_tran, false);
329        let o_prot = TBinaryOutputProtocol::new(o_tran, true);
330    
331        let mut client = IPCChainTesterSyncClient::new(i_prot, o_prot);
332        client.init_vm_api().unwrap();
333        init_vm_api_client(); //init vm api client
334
335        client.init_apply_request().unwrap();
336        crate::server::init_apply_request_server(); //init apply request server
337
338        self.client = Some(client);
339
340    }
341
342    pub fn close(&mut self) {
343        if self.client.is_some() {
344            self.client = None;
345        }
346    }
347}
348
349impl Deref for ChainTesterClient {
350    type Target = IPCChainTesterSyncClient<ClientInputProtocol, ClientOutputProtocol>;
351
352    fn deref(&self) -> &IPCChainTesterSyncClient<ClientInputProtocol, ClientOutputProtocol>
353    {
354        self.client.as_ref().unwrap()
355    }
356}
357
358impl DerefMut for ChainTesterClient {
359    fn deref_mut(&mut self) -> &mut Self::Target {
360        self.client.as_mut().unwrap()
361    }
362}
363
364pub fn get_chain_tester_client() -> MutexGuard<'static, ChainTesterClient> {
365    let mut ret = CHAIN_TESTER_CLIENT.lock().unwrap();
366    if ret.client.is_none() {
367        ret.init();
368    }
369    return ret;
370}
371
372pub fn close_chain_tester_client() {
373    let mut ret = CHAIN_TESTER_CLIENT.lock().unwrap();
374    ret.close();
375}
376
377pub struct ChainTester {
378    id: i32,
379}
380
381fn parse_ret(ret: &thrift::Result<String>) -> Result<Value> {
382    match ret {
383        Ok(ret) => {
384            // println!("+++++++parse_ret:{}", ret);
385            let tx: Value = serde_json::from_str(&ret).map_err(|err| {
386                ChainTesterError{json: None, error_string: Some(err.to_string())}
387            })?;
388
389            if tx.get("except").is_some() {
390                Err(ChainTesterError{json: Some(tx), error_string: None})
391            } else {
392                Ok(tx)
393            }
394        }
395        Err(err) => {
396            Err(ChainTesterError{
397                json: None, error_string: Some(format!("{:?}", err)),
398            })
399        }
400    }
401}
402
403fn parse_ret2(ret: &thrift::Result<Vec<u8>>) -> Result<Value> {
404    match ret {
405        Ok(ret) => {
406            let tx: Value = serde_json::from_slice(ret).map_err(|err| {
407                ChainTesterError{json: None, error_string: Some(err.to_string())}
408            })?;
409
410            if tx.get("except").is_some() {
411                Err(ChainTesterError{json: Some(tx), error_string: None})
412            } else {
413                Ok(tx)
414            }
415        }
416        Err(err) => {
417            Err(ChainTesterError{
418                json: None, error_string: Some(format!("{:?}", err)),
419            })
420        }
421    }
422}
423
424impl ChainTester {
425    pub fn new() -> Self {
426        let id = get_chain_tester_client().new_chain(true).unwrap();
427        get_apply_map_mutex().insert(id, HashMap::new());
428        Self { id }
429    }
430
431    pub fn new_ex(initialize: bool) -> Self {
432        Self { id: get_chain_tester_client().new_chain(initialize).unwrap() }
433    }
434
435    fn client(&mut self) -> MutexGuard<'static, ChainTesterClient> {
436        get_chain_tester_client()
437    }
438
439    pub fn free(&mut self) {
440        get_apply_map_mutex().remove(&self.id);
441        self.client().free_chain(self.id).unwrap();
442    }
443
444    pub fn produce_block(&mut self) {
445        self.client().produce_block(self.id, 0).unwrap()
446    }
447
448    pub fn produce_block_ex(&mut self, next_block_skip_seconds: i64) {
449        self.client().produce_block(self.id, next_block_skip_seconds).unwrap()
450    }
451
452    pub fn enable_debugging(&mut self, enable: bool) -> thrift::Result<()> {
453        self.client().enable_debugging(enable)
454    }
455
456    pub fn set_native_contract(&mut self, contract: &str, dylib: &str) -> thrift::Result<bool> {
457        self.client().set_native_contract(self.id, contract.into(), dylib.into())
458    }
459
460    pub fn set_native_apply(&mut self, contract: &str, apply: Option<FnApply>) -> thrift::Result<()> {
461        let tester_apply_map = &mut get_apply_map_mutex();
462        let apply_map = tester_apply_map.get_mut(&self.id).unwrap();
463        if let Some(_apply) = apply {
464            apply_map.insert(contract.into(), _apply);
465            self.enable_debug_contract(contract, true)?;
466        } else {
467            let _contract: String = contract.into();
468            apply_map.remove(&_contract);
469            self.enable_debug_contract(contract, false)?;
470        }
471        Ok(())
472    }
473
474    pub fn enable_debug_contract(&mut self, contract: &str, enable: bool) -> thrift::Result<()> {
475        self.client().enable_debug_contract(self.id, contract.into(), enable)
476    }
477
478    pub fn is_debug_contract_enabled(&mut self, contract: &str) -> thrift::Result<bool> {
479        self.client().is_debug_contract_enabled(self.id, contract.into())
480    }
481
482    pub fn import_key(&mut self, pub_key: &str, priv_key: &str) -> bool {
483        self.client().import_key(self.id, pub_key.into(), priv_key.into()).unwrap()
484    }
485
486    pub fn get_info(&mut self) -> Result<Value> {
487        let ret = self.client().get_info(self.id);
488        parse_ret(&ret)
489    }
490
491    pub fn create_key(&mut self) -> Result<Value> {
492        let ret = self.client().create_key("K1".into());
493        parse_ret(&ret)
494    }
495
496    pub fn create_key_ex(&mut self, key_type: &str) -> Result<Value> {
497        let ret = self.client().create_key(key_type.into());
498        parse_ret(&ret)
499    }
500
501    pub fn get_account(&mut self, account: &str) -> Result<Value> {
502        let ret = self.client().get_account(self.id, account.into());
503        parse_ret(&ret)
504    }
505
506    pub fn create_account(&mut self, creator: &str, account: &str, owner_key: &str, active_key: &str, ram_bytes: i64, stake_net: i64, stake_cpu: i64) -> Result<Value> {
507        let ret = self.client().create_account(self.id, creator.into(), account.into(), owner_key.into(), active_key.into(), ram_bytes, stake_net, stake_cpu);
508        parse_ret(&ret)
509    }
510
511    pub fn push_action(&mut self, account: &str, action: &str, arguments: ActionArguments, permissions: &str) -> Result<Value> {
512        let _account = String::from(account);
513        let _action = String::from(action);
514
515        let _permissions = String::from(permissions);
516        match self.client().push_action(self.id, _account, _action, arguments, _permissions) {
517            Ok(ret) => {
518                let tx: Value = serde_json::from_slice(&ret).map_err(|err| {
519                    ChainTesterError{json: None, error_string: Some(err.to_string())}
520                })?;
521        
522                if tx.get("except").is_some() {
523                    Err(ChainTesterError{json: Some(tx), error_string: None})
524                } else {
525                    Ok(tx)
526                }
527            }
528            Err(err) => {
529                Err(ChainTesterError{
530                    json: None, error_string: Some(format!("{:?}", err)),
531                })
532            }
533        }
534    }
535
536    pub fn deploy_contract(&mut self, account: &str, wasm_file: &str, abi_file: &str) -> Result<Value> {
537        // abi_file.is_empty()
538        let wasm = fs::read(wasm_file).unwrap();        
539        let hex_wasm = hex::encode(wasm);
540
541        let set_code_args = format!(
542            r#"
543            {{
544                "account": "{}",
545                "vmtype": 0,
546                "vmversion": 0,
547                "code": "{}"
548             }}
549            "#,
550            account,
551            hex_wasm
552        );
553
554        let permissions = format!(
555            r#"
556            {{
557                "{}": "active"
558            }}
559            "#,
560            account,
561        );
562
563        let raw_set_code_args = self.client().pack_action_args(self.id, "eosio".into(), "setcode".into(), set_code_args).unwrap();
564        let mut actions: Vec<Box<Action>> = Vec::new();
565        let setcode = Action{
566            account: Some("eosio".into()),
567            action: Some("setcode".into()),
568            permissions: Some(permissions.clone()),
569            arguments: Some(ActionArguments::RawArgs(raw_set_code_args)),
570        };
571        actions.push(Box::new(setcode));
572
573        if !abi_file.is_empty() {
574            // let abi = fs::read(Path::new(abi_file)).unwrap();
575            let abi = fs::read_to_string(abi_file).unwrap();
576            let raw_abi = self.client().pack_abi(abi).unwrap();
577            let hex_raw_abi = hex::encode(raw_abi);
578            let set_abi_args = format!(
579                r#"
580                {{
581                    "account": "{}",
582                    "abi": "{}"
583                 }}
584                "#,
585                account,
586                hex_raw_abi
587            );
588
589            let raw_setabi = self.client().pack_action_args(self.id, "eosio".into(), "setabi".into(), set_abi_args).unwrap();
590            let setabi = Action{
591                account: Some("eosio".into()),
592                action: Some("setabi".into()),
593                permissions: Some(permissions.clone()),
594                arguments: Some(ActionArguments::RawArgs(raw_setabi)),
595            };
596
597            actions.push(Box::new(setabi));    
598        }
599
600        self.push_actions(actions)
601    }
602
603    pub fn push_actions(&mut self, actions: Vec<Box<Action>>) -> Result<Value> {
604        let ret = self.client().push_actions(self.id, actions);
605        parse_ret2(&ret)
606    }
607
608    pub fn get_table_rows(&mut self, json: bool, code: &str, scope: &str, table: &str, lower_bound: &str, upper_bound: &str, limit: i64) -> Result<Value> {
609        let param = GetTableRowsPrams {
610            json: json,
611            code: code,
612            scope: scope,
613            table: table,
614            lower_bound: lower_bound,
615            upper_bound: upper_bound,
616            limit: limit,
617            key_type: "",
618            index_position: "",
619            reverse: false,
620            show_payer: true,
621        };
622        return self.get_table_rows_ex(&param);
623
624    }
625
626    pub fn get_table_rows_ex(&mut self, params: &GetTableRowsPrams) -> Result<Value> {
627        let ret = self.client().get_table_rows(self.id,
628            params.json,
629            params.code.into(),
630            params.scope.into(),
631            params.table.into(),
632            params.lower_bound.into(),
633            params.upper_bound.into(),
634            params.limit,
635            params.key_type.into(),
636            params.index_position.into(),
637            params.reverse,
638            params.show_payer,
639        );
640        parse_ret(&ret)
641    }
642
643    pub fn get_balance(&mut self, account: &str) -> u64 {
644        return self.get_balance_ex(account, "eosio.token", "EOS");
645    }
646
647    pub fn get_balance_ex(&mut self, account: &str, token_account: &str, symbol: &str) -> u64 {
648        let ret = self.get_table_rows(false, token_account, account, "accounts", symbol, "", 1).unwrap();
649        let rows = ret["rows"].as_array().unwrap();
650        println!("++++++++++++rows:{:?}", rows);
651        if rows.len() == 0 {
652            return 0;
653        }
654        let balance = rows[0].as_str().unwrap();
655        let _balance = hex::decode(balance).unwrap();
656        let amount: [u8;8] = match _balance[0..8].try_into() {
657            Ok(v) => v,
658            Err(_) => {
659                panic!("invalid value");
660            }
661        };
662        return u64::from_le_bytes(amount);
663    }
664}
665
666// pub enum ActionArguments {
667//     String(String),
668//     Binary(Vec<u8>),
669// }
670
671impl From<String> for ActionArguments {
672    fn from(value: String) -> Self {
673        ActionArguments::JsonArgs(value)
674    }
675}
676
677impl From<&str> for ActionArguments {
678    fn from(value: &str) -> Self {
679        ActionArguments::JsonArgs(String::from(value))
680    }
681}
682
683impl From<Vec<u8>> for ActionArguments {
684    fn from(value: Vec<u8>) -> Self {
685        ActionArguments::RawArgs(value)
686    }
687}
688
689impl Drop for ChainTester {
690    fn drop(&mut self) {
691        self.free();
692    }
693}
694
695pub fn new_vm_api_client(
696    host: &str,
697    port: u16,
698) -> thrift::Result<ApplySyncClient<ClientInputProtocol, ClientOutputProtocol>> {
699    let mut c = TTcpChannel::new();
700
701    // open the underlying TCP stream
702    println!("connecting to VM API server on {}:{}", host, port);
703    //wait for vm api server to start
704    thread::sleep(Duration::from_micros(10));
705    let remote_address = format!("{}:{}", host, port);
706    for i in 0..=10 {
707        match c.open(&remote_address) {
708            Ok(()) => {
709                break;
710            }
711            Err(err) => {
712                if i == 10 {
713                    panic!("{}", err)
714                } else {
715                    println!("+++++++vm_api_client error: {}", err);
716                    thread::sleep(Duration::from_micros(200));    
717                }
718            }
719        }
720    }
721
722    println!("VM API server connected!");
723
724    // clone the TCP channel into two halves, one which
725    // we'll use for reading, the other for writing
726    let (i_chan, o_chan) = c.split()?;
727
728    // wrap the raw sockets (slow) with a buffered transport of some kind
729    let i_tran = TBufferedReadTransport::new(i_chan);
730    let o_tran = TBufferedWriteTransport::new(o_chan);
731
732    // now create the protocol implementations
733    let i_prot = TBinaryInputProtocol::new(i_tran, false);
734    let o_prot = TBinaryOutputProtocol::new(o_tran, true);
735    // we're done!
736    Ok(ApplySyncClient::new(i_prot, o_prot))
737}
738
739///
740pub fn n2s(value: u64) -> String {
741	let charmap = ".12345abcdefghijklmnopqrstuvwxyz".as_bytes();
742	// 13 dots
743	let mut s: [u8; 13] = ['.' as u8, '.'  as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8, '.' as u8];
744	let mut tmp = value;
745	for i in 0..13 {
746		let c: u8;
747		if i == 0 {
748			c = charmap[(tmp&0x0f) as usize];
749		} else {
750			c = charmap[(tmp&0x1f) as usize];
751		}
752		s[12-i] = c;
753		if i == 0 {
754			tmp >>= 4
755		} else {
756			tmp >>= 5
757		}
758	}
759
760	let mut i = s.len() - 1;
761	while i != 0 {
762		if s[i] != '.' as u8 {
763			break
764		}
765        i -= 1;
766	}
767
768    let r = match String::from_utf8(s[0..i+1].to_vec()) {
769        Ok(v) => v,
770        Err(_) => String::from(""),
771    };
772    return r;
773}