Skip to content

Commit ab76ddd

Browse files
committed
Change ChainDescriptions into blobs
1 parent 9d89027 commit ab76ddd

File tree

92 files changed

+3624
-3301
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3624
-3301
lines changed

CLI.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,12 @@ Create an unassigned key pair
717717

718718
Link an owner with a key pair in the wallet to a chain that was created for that owner
719719

720-
**Usage:** `linera assign --owner <OWNER> --message-id <MESSAGE_ID>`
720+
**Usage:** `linera assign --owner <OWNER> --chain-id <CHAIN_ID>`
721721

722722
###### **Options:**
723723

724724
* `--owner <OWNER>` — The owner to assign
725-
* `--message-id <MESSAGE_ID>` — The ID of the message that created the chain. (This uniquely describes the chain and where it was created.)
725+
* `--chain-id <CHAIN_ID>` — The ID of the chain
726726

727727

728728

examples/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
resolver = "2"
33
members = [
44
"amm",
5-
"counter",
65
"call-evm-counter",
6+
"counter",
77
"counter-no-graphql",
88
"crowd-funding",
99
"ethereum-tracker",
1010
"fungible",
1111
"gen-nft",
12-
"how-to/perform-http-requests",
1312
"hex-game",
13+
"how-to/perform-http-requests",
1414
"llm",
1515
"matching-engine",
1616
"meta-counter",

examples/hex-game/src/contract.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -155,17 +155,14 @@ impl HexContract {
155155
);
156156
let app_id = self.runtime.application_id();
157157
let permissions = ApplicationPermissions::new_single(app_id.forget_abi());
158-
let (message_id, chain_id) = self.runtime.open_chain(ownership, permissions, fee_budget);
158+
let chain_id = self.runtime.open_chain(ownership, permissions, fee_budget);
159159
for owner in &players {
160160
self.state
161161
.game_chains
162162
.get_mut_or_default(owner)
163163
.await
164164
.unwrap()
165-
.insert(GameChain {
166-
message_id,
167-
chain_id,
168-
});
165+
.insert(GameChain { chain_id });
169166
}
170167
self.runtime.send_message(
171168
chain_id,

examples/hex-game/src/state.rs

-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ use serde::{Deserialize, Serialize};
1414
/// The IDs of a temporary chain for a single game of Hex.
1515
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, SimpleObject)]
1616
pub struct GameChain {
17-
/// The ID of the `OpenChain` message that created the chain.
18-
pub message_id: MessageId,
1917
/// The ID of the temporary game chain itself.
2018
pub chain_id: ChainId,
2119
}

examples/rfq/src/contract.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ impl RfqContract {
334334
);
335335
let app_id = self.runtime.application_id();
336336
let permissions = ApplicationPermissions::new_single(app_id.forget_abi());
337-
let (_, temp_chain_id) = self.runtime.open_chain(ownership, permissions, fee_budget);
337+
let temp_chain_id = self.runtime.open_chain(ownership, permissions, fee_budget);
338338

339339
// transfer tokens to the new chain
340340
let transfer = fungible::Operation::Transfer {

linera-base/src/data_types.rs

+195-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::ops;
99
#[cfg(with_metrics)]
1010
use std::sync::LazyLock;
1111
use std::{
12+
collections::BTreeMap,
1213
fmt::{self, Display},
1314
fs,
1415
hash::Hash,
@@ -31,13 +32,14 @@ use crate::prometheus_util::{
3132
exponential_bucket_latencies, register_histogram_vec, MeasureLatency,
3233
};
3334
use crate::{
34-
crypto::{BcsHashable, CryptoHash},
35+
crypto::{BcsHashable, CryptoError, CryptoHash},
3536
doc_scalar, hex_debug, http,
3637
identifiers::{
3738
ApplicationId, BlobId, BlobType, ChainId, Destination, EventId, GenericApplicationId,
3839
ModuleId, StreamId,
3940
},
4041
limited_writer::{LimitedWriter, LimitedWriterError},
42+
ownership::ChainOwnership,
4143
time::{Duration, SystemTime},
4244
vm::VmRuntime,
4345
};
@@ -707,12 +709,179 @@ impl Amount {
707709
}
708710
}
709711

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+
710877
/// Permissions for applications on a chain.
711878
#[derive(
712879
Default,
713880
Debug,
714881
PartialEq,
715882
Eq,
883+
PartialOrd,
884+
Ord,
716885
Hash,
717886
Clone,
718887
Serialize,
@@ -1060,6 +1229,13 @@ impl BlobContent {
10601229
BlobContent::new(BlobType::Committee, committee)
10611230
}
10621231

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+
10631239
/// Gets a reference to the blob's bytes.
10641240
pub fn bytes(&self) -> &[u8] {
10651241
&self.bytes
@@ -1121,7 +1297,7 @@ impl Blob {
11211297
Blob::new(BlobContent::new_data(bytes))
11221298
}
11231299

1124-
/// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1300+
/// Creates a new contract bytecode [`Blob`] from the provided bytes.
11251301
pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
11261302
Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
11271303
}
@@ -1131,19 +1307,28 @@ impl Blob {
11311307
Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
11321308
}
11331309

1134-
/// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1310+
/// Creates a new service bytecode [`Blob`] from the provided bytes.
11351311
pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
11361312
Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
11371313
}
11381314

1139-
/// Creates a new application description [`BlobContent`] from the provided
1140-
/// description.
1315+
/// Creates a new application description [`Blob`] from the provided description.
11411316
pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
11421317
Blob::new(BlobContent::new_application_description(
11431318
application_description,
11441319
))
11451320
}
11461321

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+
11471332
/// A content-addressed blob ID i.e. the hash of the `Blob`.
11481333
pub fn id(&self) -> BlobId {
11491334
BlobId {
@@ -1251,6 +1436,11 @@ doc_scalar!(
12511436
Round,
12521437
"A number to identify successive attempts to decide a value in a consensus protocol."
12531438
);
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");
12541444
doc_scalar!(OracleResponse, "A record of a single oracle response.");
12551445
doc_scalar!(BlobContent, "A blob of binary data.");
12561446
doc_scalar!(

0 commit comments

Comments
 (0)