@@ -9,6 +9,7 @@ use std::ops;
9
9
#[ cfg( with_metrics) ]
10
10
use std:: sync:: LazyLock ;
11
11
use std:: {
12
+ collections:: BTreeMap ,
12
13
fmt:: { self , Display } ,
13
14
fs,
14
15
hash:: Hash ,
@@ -31,13 +32,14 @@ use crate::prometheus_util::{
31
32
exponential_bucket_latencies, register_histogram_vec, MeasureLatency ,
32
33
} ;
33
34
use crate :: {
34
- crypto:: { BcsHashable , CryptoHash } ,
35
+ crypto:: { BcsHashable , CryptoError , CryptoHash } ,
35
36
doc_scalar, hex_debug, http,
36
37
identifiers:: {
37
38
ApplicationId , BlobId , BlobType , ChainId , Destination , EventId , GenericApplicationId ,
38
39
ModuleId , StreamId ,
39
40
} ,
40
41
limited_writer:: { LimitedWriter , LimitedWriterError } ,
42
+ ownership:: ChainOwnership ,
41
43
time:: { Duration , SystemTime } ,
42
44
vm:: VmRuntime ,
43
45
} ;
@@ -707,12 +709,179 @@ impl Amount {
707
709
}
708
710
}
709
711
712
+ /// What created a chain.
713
+ #[ derive( Eq , PartialEq , Ord , PartialOrd , Copy , Clone , Hash , Debug , Serialize , Deserialize ) ]
714
+ pub enum ChainOrigin {
715
+ /// The chain was created by the genesis configuration.
716
+ Root ( u32 ) ,
717
+ /// The chain was created by a call from another chain.
718
+ Child {
719
+ /// The parent of this chain.
720
+ parent : ChainId ,
721
+ /// The block height in the parent at which this chain was created.
722
+ block_height : BlockHeight ,
723
+ /// The index of this chain among chains created at the same block height in the parent
724
+ /// chain.
725
+ chain_index : u32 ,
726
+ } ,
727
+ }
728
+
729
+ impl ChainOrigin {
730
+ /// Whether the chain was created by another chain.
731
+ pub fn is_child ( & self ) -> bool {
732
+ matches ! ( self , ChainOrigin :: Child { .. } )
733
+ }
734
+ }
735
+
736
+ /// A number identifying the configuration of the chain (aka the committee).
737
+ #[ derive( Eq , PartialEq , Ord , PartialOrd , Copy , Clone , Hash , Default , Debug ) ]
738
+ pub struct Epoch ( pub u32 ) ;
739
+
740
+ impl Epoch {
741
+ /// The zero epoch.
742
+ pub const ZERO : Epoch = Epoch ( 0 ) ;
743
+ }
744
+
745
+ impl Serialize for Epoch {
746
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
747
+ where
748
+ S : serde:: ser:: Serializer ,
749
+ {
750
+ if serializer. is_human_readable ( ) {
751
+ serializer. serialize_str ( & self . 0 . to_string ( ) )
752
+ } else {
753
+ serializer. serialize_newtype_struct ( "Epoch" , & self . 0 )
754
+ }
755
+ }
756
+ }
757
+
758
+ impl < ' de > Deserialize < ' de > for Epoch {
759
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
760
+ where
761
+ D : serde:: de:: Deserializer < ' de > ,
762
+ {
763
+ if deserializer. is_human_readable ( ) {
764
+ let s = String :: deserialize ( deserializer) ?;
765
+ Ok ( Epoch ( u32:: from_str ( & s) . map_err ( serde:: de:: Error :: custom) ?) )
766
+ } else {
767
+ #[ derive( Deserialize ) ]
768
+ #[ serde( rename = "Epoch" ) ]
769
+ struct EpochDerived ( u32 ) ;
770
+
771
+ let value = EpochDerived :: deserialize ( deserializer) ?;
772
+ Ok ( Self ( value. 0 ) )
773
+ }
774
+ }
775
+ }
776
+
777
+ impl std:: fmt:: Display for Epoch {
778
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: result:: Result < ( ) , std:: fmt:: Error > {
779
+ write ! ( f, "{}" , self . 0 )
780
+ }
781
+ }
782
+
783
+ impl std:: str:: FromStr for Epoch {
784
+ type Err = CryptoError ;
785
+
786
+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
787
+ Ok ( Epoch ( s. parse ( ) ?) )
788
+ }
789
+ }
790
+
791
+ impl From < u32 > for Epoch {
792
+ fn from ( value : u32 ) -> Self {
793
+ Epoch ( value)
794
+ }
795
+ }
796
+
797
+ impl Epoch {
798
+ /// Tries to return an epoch with a number increased by one. Returns an error if an overflow
799
+ /// happens.
800
+ #[ inline]
801
+ pub fn try_add_one ( self ) -> Result < Self , ArithmeticError > {
802
+ let val = self . 0 . checked_add ( 1 ) . ok_or ( ArithmeticError :: Overflow ) ?;
803
+ Ok ( Self ( val) )
804
+ }
805
+
806
+ /// Tries to add one to this epoch's number. Returns an error if an overflow happens.
807
+ #[ inline]
808
+ pub fn try_add_assign_one ( & mut self ) -> Result < ( ) , ArithmeticError > {
809
+ self . 0 = self . 0 . checked_add ( 1 ) . ok_or ( ArithmeticError :: Overflow ) ?;
810
+ Ok ( ( ) )
811
+ }
812
+ }
813
+
814
+ /// The configuration for a new chain.
815
+ #[ derive( Debug , PartialEq , Eq , PartialOrd , Ord , Hash , Clone , Serialize , Deserialize ) ]
816
+ pub struct OpenChainConfig {
817
+ /// The ownership configuration of the new chain.
818
+ pub ownership : ChainOwnership ,
819
+ /// The ID of the admin chain.
820
+ pub admin_id : Option < ChainId > ,
821
+ /// The epoch in which the chain is created.
822
+ pub epoch : Epoch ,
823
+ /// Blob IDs of the committees corresponding to epochs.
824
+ pub committees : BTreeMap < Epoch , Vec < u8 > > ,
825
+ /// The initial chain balance.
826
+ pub balance : Amount ,
827
+ /// The initial application permissions.
828
+ pub application_permissions : ApplicationPermissions ,
829
+ }
830
+
831
+ /// How to create a chain.
832
+ #[ derive( Eq , PartialEq , Ord , PartialOrd , Clone , Hash , Debug , Serialize , Deserialize ) ]
833
+ pub struct ChainDescription {
834
+ origin : ChainOrigin ,
835
+ timestamp : Timestamp ,
836
+ config : OpenChainConfig ,
837
+ }
838
+
839
+ impl ChainDescription {
840
+ /// Creates a new [`ChainDescription`].
841
+ pub fn new ( origin : ChainOrigin , config : OpenChainConfig , timestamp : Timestamp ) -> Self {
842
+ Self {
843
+ origin,
844
+ config,
845
+ timestamp,
846
+ }
847
+ }
848
+
849
+ /// Returns the [`ChainId`] based on this [`ChainDescription`].
850
+ pub fn id ( & self ) -> ChainId {
851
+ ChainId :: from ( self )
852
+ }
853
+
854
+ /// Returns the [`ChainOrigin`] describing who created this chain.
855
+ pub fn origin ( & self ) -> ChainOrigin {
856
+ self . origin
857
+ }
858
+
859
+ /// Returns a reference to the [`OpenChainConfig`] of the chain.
860
+ pub fn config ( & self ) -> & OpenChainConfig {
861
+ & self . config
862
+ }
863
+
864
+ /// Returns the timestamp of when the chain was created.
865
+ pub fn timestamp ( & self ) -> Timestamp {
866
+ self . timestamp
867
+ }
868
+
869
+ /// Whether the chain was created by another chain.
870
+ pub fn is_child ( & self ) -> bool {
871
+ self . origin . is_child ( )
872
+ }
873
+ }
874
+
875
+ impl BcsHashable < ' _ > for ChainDescription { }
876
+
710
877
/// Permissions for applications on a chain.
711
878
#[ derive(
712
879
Default ,
713
880
Debug ,
714
881
PartialEq ,
715
882
Eq ,
883
+ PartialOrd ,
884
+ Ord ,
716
885
Hash ,
717
886
Clone ,
718
887
Serialize ,
@@ -1060,6 +1229,13 @@ impl BlobContent {
1060
1229
BlobContent :: new ( BlobType :: Committee , committee)
1061
1230
}
1062
1231
1232
+ /// Creates a new chain description [`BlobContent`] from a [`ChainDescription`].
1233
+ pub fn new_chain_description ( chain_description : & ChainDescription ) -> Self {
1234
+ let bytes = bcs:: to_bytes ( & chain_description)
1235
+ . expect ( "Serializing a ChainDescription should not fail!" ) ;
1236
+ BlobContent :: new ( BlobType :: ChainDescription , bytes)
1237
+ }
1238
+
1063
1239
/// Gets a reference to the blob's bytes.
1064
1240
pub fn bytes ( & self ) -> & [ u8 ] {
1065
1241
& self . bytes
@@ -1121,7 +1297,7 @@ impl Blob {
1121
1297
Blob :: new ( BlobContent :: new_data ( bytes) )
1122
1298
}
1123
1299
1124
- /// Creates a new contract bytecode [`BlobContent `] from the provided bytes.
1300
+ /// Creates a new contract bytecode [`Blob `] from the provided bytes.
1125
1301
pub fn new_contract_bytecode ( compressed_bytecode : CompressedBytecode ) -> Self {
1126
1302
Blob :: new ( BlobContent :: new_contract_bytecode ( compressed_bytecode) )
1127
1303
}
@@ -1131,19 +1307,28 @@ impl Blob {
1131
1307
Blob :: new ( BlobContent :: new_evm_bytecode ( compressed_bytecode) )
1132
1308
}
1133
1309
1134
- /// Creates a new service bytecode [`BlobContent `] from the provided bytes.
1310
+ /// Creates a new service bytecode [`Blob `] from the provided bytes.
1135
1311
pub fn new_service_bytecode ( compressed_bytecode : CompressedBytecode ) -> Self {
1136
1312
Blob :: new ( BlobContent :: new_service_bytecode ( compressed_bytecode) )
1137
1313
}
1138
1314
1139
- /// Creates a new application description [`BlobContent`] from the provided
1140
- /// description.
1315
+ /// Creates a new application description [`Blob`] from the provided description.
1141
1316
pub fn new_application_description ( application_description : & ApplicationDescription ) -> Self {
1142
1317
Blob :: new ( BlobContent :: new_application_description (
1143
1318
application_description,
1144
1319
) )
1145
1320
}
1146
1321
1322
+ /// Creates a new committee [`Blob`] from the provided bytes.
1323
+ pub fn new_committee ( committee : impl Into < Box < [ u8 ] > > ) -> Self {
1324
+ Blob :: new ( BlobContent :: new_committee ( committee) )
1325
+ }
1326
+
1327
+ /// Creates a new chain description [`Blob`] from a [`ChainDescription`].
1328
+ pub fn new_chain_description ( chain_description : & ChainDescription ) -> Self {
1329
+ Blob :: new ( BlobContent :: new_chain_description ( chain_description) )
1330
+ }
1331
+
1147
1332
/// A content-addressed blob ID i.e. the hash of the `Blob`.
1148
1333
pub fn id ( & self ) -> BlobId {
1149
1334
BlobId {
@@ -1251,6 +1436,11 @@ doc_scalar!(
1251
1436
Round ,
1252
1437
"A number to identify successive attempts to decide a value in a consensus protocol."
1253
1438
) ;
1439
+ doc_scalar ! (
1440
+ Epoch ,
1441
+ "A number identifying the configuration of the chain (aka the committee)"
1442
+ ) ;
1443
+ doc_scalar ! ( ChainDescription , "How to create a chain" ) ;
1254
1444
doc_scalar ! ( OracleResponse , "A record of a single oracle response." ) ;
1255
1445
doc_scalar ! ( BlobContent , "A blob of binary data." ) ;
1256
1446
doc_scalar ! (
0 commit comments