redgold_schema/
lib.rs

1#![allow(unused_imports)]
2#![allow(dead_code)]
3use anyhow::{Context, Result};
4use backtrace::Backtrace;
5use itertools::Itertools;
6use prost::{DecodeError, Message};
7use serde::Serialize;
8use std::fmt::Display;
9use std::future::Future;
10use std::str::FromStr;
11use std::sync::atomic::{AtomicBool, Ordering};
12
13use crate::structs::{AboutNodeRequest, BytesDecoder, ContentionKey, NetworkEnvironment, NodeMetadata, PeerId, PeerMetadata, PublicKey, PublicRequest, PublicResponse, SignatureType, StateSelector};
14use crate::message::{Request, Response};
15use crate::util::task_local::task_local_impl::task_local_error_details;
16use observability::errors::EnhanceErrorInfo;
17use proto_serde::{ProtoHashable, ProtoSerde};
18use structs::{
19    Address, BytesData, ErrorCode, ErrorInfo, Hash, HashFormatType, ResponseMetadata,
20    StructMetadata, Transaction,
21};
22use util::{lang_util, times};
23
24pub mod structs {
25    include!(concat!(env!("OUT_DIR"), "/structs.rs"));
26}
27
28pub mod execution {
29    include!(concat!(env!("OUT_DIR"), "/execution.rs"));
30}
31
32pub mod airgap {
33    include!(concat!(env!("OUT_DIR"), "/airgap.rs"));
34}
35
36pub mod parties {
37    include!(concat!(env!("OUT_DIR"), "/parties.rs"));
38}
39
40pub mod message {
41    include!(concat!(env!("OUT_DIR"), "/message.rs"));
42}
43
44pub mod external {
45    include!(concat!(env!("OUT_DIR"), "/external.rs"));
46}
47
48pub mod transact {
49    include!(concat!(env!("OUT_DIR"), "/transact.rs"));
50}
51
52
53pub mod address;
54pub mod hash;
55pub mod block;
56pub mod constants;
57pub mod observation;
58pub mod output;
59pub mod proof;
60pub mod transaction;
61pub mod util;
62pub mod utxo_entry;
63pub mod utxo_id;
64pub mod merkle_proof;
65pub mod response;
66pub mod servers;
67pub mod peers;
68pub mod multiparty;
69pub mod signature;
70pub mod udp;
71pub mod control;
72pub mod public_key;
73pub mod seeds;
74pub mod trust;
75pub mod input;
76pub mod debug_version;
77pub mod transaction_info;
78pub mod exec;
79pub mod contract;
80pub mod weighting;
81pub mod pow;
82pub mod tx_schema_validate;
83pub mod fee_validator;
84pub mod observability;
85pub mod proto_serde;
86pub mod helpers;
87pub mod party;
88pub mod tx;
89pub mod config_data;
90pub mod portfolio;
91pub mod conf;
92pub mod data_folder;
93pub mod errors;
94pub mod peer;
95pub mod explorer;
96pub mod supported_currency;
97pub mod airgap_msg;
98pub mod keys;
99
100impl BytesData {
101    pub fn from(data: Vec<u8>) -> Self {
102        BytesData {
103            value: data,
104            decoder: BytesDecoder::Standard as i32,
105            version: constants::STANDARD_VERSION,
106        }
107    }
108}
109
110pub fn bytes_data(data: Vec<u8>) -> Option<BytesData> {
111    Some(BytesData::from(data))
112}
113
114pub const VERSION: u32 = 0;
115
116pub fn i64_from_string(value: String) -> Result<i64, ErrorInfo> {
117    value.parse::<i64>().map_err(|_| {
118        error_message(
119            ErrorCode::ParseFailure,
120            "unable to parse i64 value from string amount",
121        )
122    })
123}
124
125pub fn from_hex(hex_value: String) -> Result<Vec<u8>, ErrorInfo> {
126    hex::decode(hex_value.clone()).map_err(|e| {
127        error_message(
128            ErrorCode::HexDecodeFailure,
129            format!("Error decoding hex string value to bytes: {} {}", hex_value, e.to_string()),
130        )
131    })
132}
133
134pub fn from_hex_ref(hex_value: &String) -> Result<Vec<u8>, ErrorInfo> {
135    hex::decode(hex_value).map_err(|e| {
136        error_message(
137            ErrorCode::HexDecodeFailure,
138            format!("Error decoding hex string value to bytes: {} {}", hex_value, e.to_string()),
139        )
140    })
141}
142
143//
144//
145// impl<T> Into<Result<T, ErrorInfo>> for Option<T> {
146//     fn into(self) -> T {
147//
148//     }
149// }
150
151pub fn struct_metadata(time: i64) -> Option<StructMetadata> {
152    Some(StructMetadata {
153        time: Some(time),
154        version: VERSION as i32,
155        hash: None,
156        signable_hash: None,
157        signed_hash: None,
158        counter_party_hash: None,
159        confirmation_hash: None,
160    })
161}
162
163pub fn struct_metadata_new() -> Option<StructMetadata> {
164    struct_metadata(times::current_time_millis())
165}
166//
167// pub trait SafeBytesAccess {
168//     fn safe_bytes(&self) -> Result<Vec<u8>, ErrorInfo>;
169// }
170//
171// impl SafeBytesAccess for Option<BytesData> {
172//     fn safe_bytes(&self) -> Result<Vec<u8>, ErrorInfo> {
173//         Ok(self
174//             .as_ref() // TODO: parent Field message? necessary or not?
175//             .ok_or(error_message(ErrorCode::MissingField, "bytes data"))?
176//             .value
177//             .clone())
178//     }
179// }
180//
181//
182// //
183// // impl SafeBytesAccess for Option<Hash> {
184// //     fn safe_bytes(&self) -> Result<Vec<u8>, ErrorInfo> {
185// //         Ok(self
186// //             .as_ref() // TODO: parent Field message? necessary or not?
187// //             .ok_or(error_message(Error::MissingField, "hash"))?
188// //             .bytes
189// //             .safe_bytes()?)
190// //     }
191// // }
192// //
193// // impl SafeBytesAccess for Hash {
194// //     fn safe_bytes(&self) -> Result<Vec<u8>, ErrorInfo> {
195// //         self.proto_serialize()
196// //     }
197// // }
198//
199// impl SafeBytesAccess for Option<Address> {
200//     fn safe_bytes(&self) -> Result<Vec<u8>, ErrorInfo> {
201//         Ok(self
202//             .as_ref() // TODO: parent Field message? necessary or not?
203//             .ok_or(error_message(ErrorCode::MissingField, "address"))?
204//             .address
205//             .safe_bytes()?)
206//     }
207// }
208//
209// impl SafeBytesAccess for Option<PublicKey> {
210//     fn safe_bytes(&self) -> RgResult<Vec<u8>> {
211//         Ok(self
212//             .as_ref() // TODO: parent Field message? necessary or not?
213//             .ok_or(error_message(ErrorCode::MissingField, "Missing public key"))?
214//             .bytes
215//             .safe_bytes()?
216//         )
217//     }
218// }
219//
220// impl SafeBytesAccess for Option<PeerId> {
221//     fn safe_bytes(&self) -> RgResult<Vec<u8>> {
222//         Ok(self
223//             .as_ref() // TODO: parent Field message? necessary or not?
224//             .ok_or(error_message(ErrorCode::MissingField, "Missing peerid"))?
225//             .peer_id
226//             .safe_bytes()?
227//         )
228//     }
229// }
230//
231// impl<T> SafeBytesAccess for Option<T>
232// where T: SafeBytesAccess + Sized
233// {
234//     fn safe_bytes(&self) -> RgResult<Vec<u8>> {
235//         Ok(self
236//             .as_ref() // TODO: parent Field message? necessary or not?
237//             .ok_or(error_message(ErrorCode::MissingField, "Missing safe bytes field"))?
238//             .safe_bytes()?
239//         )
240//     }
241// }
242
243impl std::fmt::Display for Hash {
244    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245        write!(
246            f,
247            "{}",
248            self.hex()
249        )
250    }
251}
252
253pub trait HashClear {
254    fn hash_clear(&mut self);
255}
256
257/*
258
259trait AddAny
260where Self: Sized + Add<Self, Output=Self>,
261for<'b> Self: Add<&'b Self, Output=Self>,
262{}
263
264impl<T> AddAny for T
265where T: Add<T, Output=T>,
266for<'b> T: Add<&'b T, Output=T>,
267{}
268
269fn add_val_val<T: AddAny>(x: T, y: T) -> T { x + y }
270fn add_val_ref<T: AddAny>(x: T, y: &T) -> T { x + y }
271 */
272//
273
274//
275// struct CurrencyTransferTransaction {
276//     transaction: Transaction
277// }
278pub trait SafeOption<T> {
279    fn safe_get(&self) -> Result<&T, ErrorInfo>;
280    fn safe_get_msg<S: Into<String>>(&self, msg: S) -> Result<&T, ErrorInfo>;
281    // TODO: put in another trait with a clone bound
282    // fn safe_get_clone(&self) -> Result<T, ErrorInfo>;
283    fn ok_msg(self, err: impl Into<String>) -> Result<T, ErrorInfo>;
284}
285//
286// pub trait SafeOptionJson<T> {
287//     fn safe_get_or_json(&self) -> Result<&T, ErrorInfo>;
288// }
289//
290//
291// impl<T> SafeOptionJson<T> for Option<T> where T: Serialize {
292//     fn safe_get_or_json(&self) -> Result<&T, ErrorInfo> {
293//         self.as_ref().ok_or(error_message(Error::MissingField, serde_json::to_string(&self).unwrap_or("Json serialization error of missing field data".to_string())))
294//     }
295// }
296
297
298// #[inline]
299// #[stable(feature = "rust1", since = "1.0.0")]
300// pub fn ok_or<E>(self, err: E) -> Result<T, E> {
301//     match self {
302//         Some(v) => Ok(v),
303//         None => Err(err),
304//     }
305// }
306
307impl<T> SafeOption<T> for Option<T> {
308    fn safe_get(&self) -> Result<&T, ErrorInfo> {
309        self.as_ref().ok_or(error_message(
310            ErrorCode::MissingField,
311            "unspecified optional value",
312        ))
313    }
314    fn safe_get_msg<S: Into<String>>(&self, msg: S) -> Result<&T, ErrorInfo> {
315        self // TODO: parent Field message? necessary or not?
316            .as_ref()
317            .ok_or(error_message(
318                ErrorCode::MissingField,
319                format!("{} option empty", msg.into()),
320            ))
321    }
322    fn ok_msg(self, err: impl Into<String>) -> RgResult<T> {
323        match self {
324            Some(v) => Ok(v),
325            None => Err(error_info(err.into())),
326        }
327    }
328
329}
330
331pub fn response_metadata() -> Option<ResponseMetadata> {
332    let mut response_metadata = ResponseMetadata::default();
333    response_metadata.success = true;
334    Some(response_metadata)
335}
336
337#[test]
338fn bool_defaults() {
339    let metadata = ResponseMetadata::default();
340    println!("metadata: {:?}", metadata);
341    assert_eq!(false, metadata.success);
342}
343
344
345pub trait ErrorInfoContext<T, E> {
346    /// Wrap the error value with additional context.
347    fn error_info<C: Into<String>>(self, context: C) -> Result<T, ErrorInfo>
348        where
349            C: Display + Send + Sync + 'static;
350    fn error_msg<C: Into<String>>(self, code: ErrorCode, context: C) -> Result<T, ErrorInfo>
351        where
352            C: Display + Send + Sync + 'static;
353
354}
355
356impl<T, E> ErrorInfoContext<T, E> for Result<T, E>
357    where
358        E: std::error::Error + Send + Sync + 'static,
359{
360    fn error_info<C: Into<String>>(self, context: C) -> Result<T, ErrorInfo>
361        where
362            C: Display + Send + Sync + 'static {
363        // Not using map_err to save 2 useless frames off the captured backtrace
364        // in ext_context.
365        // self.context(context)
366        self.map_err(|e| error_msg(ErrorCode::UnknownError, context.into(), e.to_string()))
367    }
368
369    fn error_msg<C: Into<String>>(self, code: ErrorCode, context: C) -> Result<T, ErrorInfo> where C: Display + Send + Sync + 'static {
370        self.map_err(|e| error_msg(code, context.into(), e.to_string()))
371    }
372}
373
374
375pub fn error_info<S: Into<String>>(message: S) -> ErrorInfo {
376    error_message(crate::structs::ErrorCode::UnknownError, message.into())
377}
378
379pub fn error_code(code: ErrorCode) -> ErrorInfo {
380    error_message(code, "".to_string())
381}
382
383pub fn slice_vec_eager<T>(vec: Vec<T>, start: usize, end: usize) -> Vec<T>
384where T : Clone {
385    let mut ret = vec![];
386    // let l = vec.len();
387    for (i, v) in vec.iter().enumerate() {
388        if i >= start && i <= end {
389            ret.push(v.clone());
390        }
391    }
392    ret
393}
394
395pub fn split_to_str(vec: String, splitter: &str) -> Vec<String> {
396    let mut ret = vec![];
397    for seg in vec.split(splitter) {
398        ret.push(seg.to_string());
399    }
400    ret
401}
402
403pub fn error_msg<S: Into<String>, P: Into<String>>(code: ErrorCode, message: S, lib_message: P) -> ErrorInfo {
404
405    // TODO: Determine if this helps.
406    static IS_CAPTURING: AtomicBool = AtomicBool::new(false);
407
408    let stack = if !IS_CAPTURING.swap(true, Ordering::SeqCst) {
409
410        let stacktrace = format!("{:?}", Backtrace::new());
411        let stacktrace_abridged: Vec<String> = split_to_str(stacktrace, "\n");
412        let trace = slice_vec_eager(stacktrace_abridged, 0, 50).join("\n").to_string();
413        // let trace = format!("{:?}", Backtrace::new());
414        IS_CAPTURING.store(false, Ordering::SeqCst);
415        trace
416    } else {
417        "Nested error - backtrace skipped".to_string()
418    };
419
420    let details = task_local_error_details();
421
422    ErrorInfo {
423        code: code as i32,
424        // TODO: From error code map
425        description: "".to_string(),
426        description_extended: "".to_string(),
427        message: message.into(),
428        details,
429        retriable: false,
430        stacktrace: stack,
431        lib_message: lib_message.into(),
432        abort: false,
433        skip_logging: false,
434        internal_log_level: None
435    }
436}
437
438pub fn error_message<S: Into<String>>(error_code: structs::ErrorCode, message: S) -> ErrorInfo {
439    error_msg(error_code, message, "".to_string())
440}
441
442pub fn empty_public_response() -> PublicResponse {
443    PublicResponse {
444        response_metadata: None,
445        submit_transaction_response: None,
446        query_transaction_response: None,
447        about_node_response: None,
448        query_addresses_response: None,
449        faucet_response: None,
450        recent_transactions_response: None,
451        hash_search_response: None
452    }
453}
454
455
456pub fn empty_public_request() -> PublicRequest {
457    PublicRequest {
458        submit_transaction_request: None,
459        query_transaction_request: None,
460        about_node_request: None,
461        query_addresses_request: None,
462        faucet_request: None,
463        recent_transactions_request: None,
464        hash_search_request: None
465    }
466}
467
468pub fn signature_data(data: Vec<u8>) -> Option<crate::structs::Signature> {
469    Some(structs::Signature {
470        bytes: bytes_data(data),
471        signature_type: SignatureType::Ecdsa as i32,
472        rsv: None
473    })
474}
475
476pub fn decode_hex(h: String) -> Result<Vec<u8>, ErrorInfo> {
477    from_hex(h)
478}
479
480
481impl PeerMetadata {
482    pub fn proto_serialize(&self) -> Vec<u8> {
483        return self.encode_to_vec();
484    }
485
486    pub fn proto_deserialize(bytes: Vec<u8>) -> Result<Self, DecodeError> {
487        return PeerMetadata::decode(&*bytes);
488    }
489
490}
491
492impl HashClear for Request {
493    fn hash_clear(&mut self) {
494
495        self.proof = None;
496        self.origin = None;
497
498    }
499}
500
501impl Request {
502    pub fn serialize(&self) -> Vec<u8> {
503        return self.encode_to_vec();
504    }
505
506    pub fn deserialize(bytes: Vec<u8>) -> Result<Self, DecodeError> {
507        return Request::decode(&*bytes);
508    }
509
510    pub fn empty() -> Self {
511        Request::default()
512    }
513
514    pub fn about(&mut self) -> Self {
515        self.about_node_request = Some(AboutNodeRequest{verbose: true});
516        self.clone()
517    }
518
519    pub fn with_metadata(mut self, node_metadata: NodeMetadata) -> Request {
520        self.node_metadata = Some(node_metadata);
521        self
522    }
523
524    pub fn auth_required(&self) -> bool {
525        self.initiate_keygen.is_some() || self.initiate_signing.is_some()
526    }
527
528}
529
530
531
532#[cfg(test)]
533mod tests {
534    #[test]
535    fn it_works() {
536        // let result = add(2, 2);
537        // assert_eq!(result, 4);
538    }
539}
540
541impl NetworkEnvironment {
542
543    pub fn btc_explorer_link(&self) -> String {
544        let mut net = "testnet/";
545        if self.is_main() {
546            net = "";
547        }
548        format!("https://blockstream.info/{net}")
549    }
550
551    pub fn btc_address_link(&self, address: String) -> String {
552        format!("{}address/{}", self.btc_explorer_link(), address)
553    }
554
555
556    pub fn btc_tx_link(&self, address: String) -> String {
557        format!("{}tx/{}", self.btc_explorer_link(), address)
558    }
559
560    pub fn eth_explorer_link(&self) -> String {
561        let eth_url = if self.is_main() {
562            "https://etherscan.io"
563        } else {
564            "https://sepolia.etherscan.io"
565        };
566        eth_url.to_string()
567    }
568
569    pub fn eth_address_link(&self, eth_address: String) -> String {
570        format!("{}/address/{}", self.eth_explorer_link(), eth_address)
571    }
572
573    pub fn eth_tx_link(&self, txid: String) -> String {
574        format!("{}/tx/{}", self.eth_explorer_link(), txid)
575    }
576
577
578    pub fn explorer_link(&self) -> String {
579        let self_str = self.to_std_string();
580        let pfx = if self.is_main() {
581            "".to_string()
582        } else {
583            format!("{}.", self_str)
584        };
585      format!("https://{}explorer.redgold.io", pfx)
586    }
587
588    pub fn explorer_hash_link(&self, hash: String) -> String {
589        format!("{}/hash/{}", self.explorer_link(), hash)
590    }
591
592    pub fn to_std_string(&self) -> String {
593        format!("{:?}", &self).to_lowercase()
594    }
595    pub fn parse(from_str: String) -> Self {
596        let mut n = from_str.clone();
597        let string2 = lang_util::make_ascii_titlecase(&mut *n);
598        NetworkEnvironment::from_str(&*string2).expect("error parsing network environment")
599    }
600    pub fn parse_safe(from_str: String) -> Result<Self, ErrorInfo> {
601        let mut n = from_str.clone();
602        let string2 = lang_util::make_ascii_titlecase(&mut *n);
603        NetworkEnvironment::from_str(&*string2).error_info("error parsing network environment")
604    }
605
606    pub fn from_std_string(s: impl Into<String>) -> RgResult<Self> {
607        Self::parse_safe(s.into())
608    }
609
610    pub fn status_networks() -> Vec<NetworkEnvironment> {
611        vec![
612            NetworkEnvironment::Main,
613            NetworkEnvironment::Test,
614            NetworkEnvironment::Staging,
615            NetworkEnvironment::Dev,
616            NetworkEnvironment::Predev,
617        ]
618    }
619
620    pub fn gui_networks() -> Vec<NetworkEnvironment> {
621        vec![
622            NetworkEnvironment::Main,
623            NetworkEnvironment::Test,
624            NetworkEnvironment::Staging,
625            NetworkEnvironment::Dev,
626            NetworkEnvironment::Predev,
627        ]
628    }
629
630    pub fn is_local_debug(&self) -> bool {
631        vec![
632            NetworkEnvironment::Debug, NetworkEnvironment::Local
633        ].contains(self)
634    }
635
636    pub fn is_main_stage_network(&self) -> bool {
637        Self::status_networks().contains(self)
638    }
639
640    pub fn is_all(&self) -> bool {
641        self == &NetworkEnvironment::All
642    }
643
644    pub fn is_main(&self) -> bool {
645        self == &NetworkEnvironment::Main
646    }
647    pub fn is_dev(&self) -> bool {
648        self == &NetworkEnvironment::Dev
649    }
650
651    pub fn default_port_offset(&self) -> u16 {
652        let port = match self {
653            NetworkEnvironment::Main => {16180}
654            NetworkEnvironment::Test => {16280}
655            NetworkEnvironment::Staging => {16380}
656            NetworkEnvironment::Dev => {16480}
657            NetworkEnvironment::Predev => {16580}
658            NetworkEnvironment::Perf => {16680}
659            NetworkEnvironment::Integration => {16780}
660            NetworkEnvironment::Local => {16880}
661            NetworkEnvironment::Debug => {16980}
662            NetworkEnvironment::All => {17080}
663        };
664        port as u16
665    }
666}
667
668#[test]
669fn network_environment_ser() {
670    use std::str::FromStr;
671    println!("{}", format!("{:?}", NetworkEnvironment::Local).to_lowercase());
672    assert_eq!(NetworkEnvironment::Local.to_std_string(), "local");
673}
674
675impl PublicResponse {
676    pub fn accepted(&self) -> bool {
677        self.response_metadata
678            .as_ref()
679            .map(|x| x.success)
680            .unwrap_or(false)
681    }
682    pub fn error_code(&self) -> Option<i32> {
683        self.response_metadata
684            .clone()
685            .and_then(|r| r.error_info.map(|e| e.code))
686    }
687    pub fn error_info(&self) -> Option<ErrorInfo> {
688        self.response_metadata
689            .clone()
690            .and_then(|r| r.error_info)
691    }
692    pub fn as_error(&self) -> Result<Self, ErrorInfo> {
693        self.error_info().map(|o| Err(o)).unwrap_or(Ok(self.clone()))
694    }
695}
696
697impl PeerId {
698    pub fn from_bytes_direct(bytes: Vec<u8>) -> Self {
699        Self {
700            peer_id: Some(PublicKey::from_bytes_direct_ecdsa(bytes)),
701        }
702    }
703
704    pub fn from_pk(pk: PublicKey) -> Self {
705        Self {
706            peer_id: Some(pk),
707        }
708    }
709
710    pub fn raw_hex_or_from_public_key(&self) -> String {
711        self.peer_id.as_ref().map(|x| x.hex()).unwrap_or("missing peer id".to_string())
712    }
713
714
715}
716
717impl HashClear for StructMetadata {
718    fn hash_clear(&mut self) {
719        self.hash = None;
720        self.signable_hash = None;
721        self.signed_hash = None;
722        self.counter_party_hash = None;
723        self.confirmation_hash = None;
724    }
725}
726
727impl StructMetadata {
728
729}
730
731pub trait ShortString {
732    fn short_string(&self) -> Result<String, ErrorInfo>;
733    fn first_four_last_four_ellipses(&self) -> Result<String, ErrorInfo>;
734    fn last_n(&self, n: impl Into<i32>) -> Result<String, ErrorInfo>;
735    fn first_n(&self, n: impl Into<i32>) -> Result<String, ErrorInfo>;
736}
737
738impl ShortString for String {
739    fn short_string(&self) -> Result<String, ErrorInfo> {
740        self.last_n(6)
741    }
742
743    fn first_four_last_four_ellipses(&self) -> Result<String, ErrorInfo> {
744        let exclude_prefixes = ["0a220a20", "0a230a2103", "0a230a2102"];
745        let stripped = {
746            exclude_prefixes.iter()
747                .find(|&prefix| self.starts_with(prefix))
748                .map(|prefix| self[prefix.len()..].to_string())
749                .unwrap_or_else(|| self.clone())
750        };
751
752        let first_4 = stripped.first_n(4)?;
753        let last_4 = self.last_n(4)?;
754        Ok(format!("{}...{}", first_4, last_4))
755    }
756
757    fn last_n(&self, n: impl Into<i32>) -> Result<String, ErrorInfo> {
758        let len = self.len();
759        let start = (len as i32) - n.into();
760        if start < 0 {
761            return Ok("".to_string());
762            // return Err(error_info("string too short to short_string"));
763        }
764        let start = start as usize;
765        let x = &self[start..len];
766        Ok(x.to_string())
767    }
768
769    fn first_n(&self, n: impl Into<i32>) -> Result<String, ErrorInfo> {
770        let len = self.len();
771        let start = 0i32;
772        let end = n.into() as usize;
773        if len < end {
774            return Err(error_info("string too short to short_string"));
775        }
776        let start = start as usize;
777        let x = &self[start..end];
778        Ok(x.to_string())
779    }
780
781}
782
783pub type RgResult<T> = Result<T, ErrorInfo>;
784
785
786impl HashClear for BytesData {
787    fn hash_clear(&mut self) {}
788}
789
790impl HashClear for structs::ContentionKey {
791    fn hash_clear(&mut self) {}
792}
793
794impl ContentionKey {
795    pub fn contract_request(address: &Address, selector: Option<&StateSelector>) -> ContentionKey {
796        let mut s = Self::default();
797        s.address = Some(address.clone());
798        s.selector = selector.cloned();
799        s
800    }
801}