@@ -12,16 +12,18 @@ use std::str::FromStr;
1212use std:: string:: String ;
1313use std:: vec:: Vec ;
1414
15- use anyhow:: anyhow;
15+ use anyhow:: { anyhow, bail } ;
1616use fastcrypto:: encoding:: { decode_bytes_hex, Encoding , Hex } ;
1717use fastcrypto:: hash:: HashFunction ;
1818use rand:: Rng ;
1919use schemars:: JsonSchema ;
2020use serde:: ser:: Error ;
21- use serde:: { Deserialize , Serialize } ;
22- use serde_with:: serde_as;
21+ use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
22+ use serde_with:: { DeserializeAs , SerializeAs , serde_as} ;
2323use Result ;
2424
25+ use iota_sdk_types:: crypto:: HashingIntentScope ;
26+
2527use crate :: move_core_types:: account_address:: AccountAddress ;
2628use crate :: move_core_types:: identifier:: IdentStr ;
2729use crate :: move_core_types:: language_storage:: { ModuleId , StructTag , TypeTag } ;
@@ -35,7 +37,7 @@ use super::dynamic_field::DynamicFieldInfo;
3537use super :: error:: { IotaError , IotaResult } ;
3638use super :: gas_coin:: { GasCoin , GAS } ;
3739use super :: governance:: { StakedIota , STAKED_IOTA_STRUCT_NAME , STAKING_POOL_MODULE_NAME } ;
38- use super :: iota_serde:: { to_iota_struct_tag_string , HexAccountAddress , Readable } ;
40+ use super :: iota_serde:: { to_custom_deser_error , to_iota_struct_tag_string , Readable } ;
3941use super :: object:: Owner ;
4042use super :: stardust:: output:: Nft ;
4143use super :: timelock:: timelock:: { self , TimeLock } ;
@@ -691,6 +693,55 @@ impl ObjectID {
691693 }
692694 }
693695
696+ /// Create an ObjectID from `TransactionDigest` and `creation_num`.
697+ /// Caller is responsible for ensuring that `creation_num` is fresh
698+ pub fn derive_id ( digest : TransactionDigest , creation_num : u64 ) -> Self {
699+ let mut hasher = DefaultHash :: default ( ) ;
700+ hasher. update ( [ HashingIntentScope :: RegularObjectId as u8 ] ) ;
701+ hasher. update ( digest) ;
702+ hasher. update ( creation_num. to_le_bytes ( ) ) ;
703+ let hash = hasher. finalize ( ) ;
704+
705+ // truncate into an ObjectID.
706+ // OK to access slice because digest should never be shorter than
707+ // ObjectID::LENGTH.
708+ ObjectID :: try_from ( & hash. as_ref ( ) [ 0 ..ObjectID :: LENGTH ] ) . unwrap ( )
709+ }
710+
711+ /// Increment the ObjectID by one, assuming the ObjectID hex is a number
712+ /// represented as an array of bytes
713+ pub fn next_increment ( & self ) -> Result < ObjectID , anyhow:: Error > {
714+ let mut prev_val = self . to_vec ( ) ;
715+ let mx = [ 0xFF ; Self :: LENGTH ] ;
716+
717+ if prev_val == mx {
718+ bail ! ( "Increment will cause overflow" ) ;
719+ }
720+
721+ // This logic increments the integer representation of an ObjectID u8 array
722+ for idx in ( 0 ..Self :: LENGTH ) . rev ( ) {
723+ if prev_val[ idx] == 0xFF {
724+ prev_val[ idx] = 0 ;
725+ } else {
726+ prev_val[ idx] += 1 ;
727+ break ;
728+ } ;
729+ }
730+ ObjectID :: try_from ( prev_val. clone ( ) ) . map_err ( |w| w. into ( ) )
731+ }
732+
733+ /// Create `count` object IDs starting with one at `offset`
734+ pub fn in_range ( offset : ObjectID , count : u64 ) -> Result < Vec < ObjectID > , anyhow:: Error > {
735+ let mut ret = Vec :: new ( ) ;
736+ let mut prev = offset;
737+ for o in 0 ..count {
738+ if o != 0 {
739+ prev = prev. next_increment ( ) ?;
740+ }
741+ ret. push ( prev) ;
742+ }
743+ Ok ( ret)
744+ }
694745
695746 /// Return the full hex string with 0x prefix without removing trailing 0s.
696747 /// Prefer this over [fn to_hex_literal] if the string needs to be fully
@@ -797,6 +848,33 @@ impl From<IotaAddress> for AccountAddress {
797848 }
798849}
799850
851+ /// Hex serde for AccountAddress
852+ struct HexAccountAddress ;
853+
854+ impl SerializeAs < AccountAddress > for HexAccountAddress {
855+ fn serialize_as < S > ( value : & AccountAddress , serializer : S ) -> Result < S :: Ok , S :: Error >
856+ where
857+ S : Serializer ,
858+ {
859+ Hex :: serialize_as ( value, serializer)
860+ }
861+ }
862+
863+ impl < ' de > DeserializeAs < ' de , AccountAddress > for HexAccountAddress {
864+ fn deserialize_as < D > ( deserializer : D ) -> Result < AccountAddress , D :: Error >
865+ where
866+ D : Deserializer < ' de > ,
867+ {
868+ let s = String :: deserialize ( deserializer) ?;
869+ if s. starts_with ( "0x" ) {
870+ AccountAddress :: from_hex_literal ( & s)
871+ } else {
872+ AccountAddress :: from_hex ( & s)
873+ }
874+ . map_err ( to_custom_deser_error :: < ' de , D , _ > )
875+ }
876+ }
877+
800878impl fmt:: Display for MoveObjectType {
801879 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
802880 let s: StructTag = self . clone ( ) . into ( ) ;
0 commit comments