598 lines
21 KiB
Rust
598 lines
21 KiB
Rust
#![allow(dead_code)]
|
|
|
|
use levcs_core::{Blob, ObjectId, ObjectType};
|
|
use levcs_identity::keys::SecretKey;
|
|
use levcs_protocol::v2::*;
|
|
use levcs_protocol::CanonicalCodec;
|
|
|
|
pub fn id(byte: u8) -> ObjectId {
|
|
ObjectId([byte; 32])
|
|
}
|
|
|
|
pub fn key(byte: u8) -> SecretKey {
|
|
SecretKey::from_seed([byte; 32])
|
|
}
|
|
|
|
pub fn evidence_context() -> AdministrativeEvidenceContextV1 {
|
|
AdministrativeEvidenceContextV1 {
|
|
destination_repo: id(3),
|
|
operation_id: [0x41; 16],
|
|
}
|
|
}
|
|
|
|
pub fn evidence_context_for(evidence: &TransactionEvidenceV1) -> AdministrativeEvidenceContextV1 {
|
|
match evidence {
|
|
TransactionEvidenceV1::LegacyMigrationV1 {
|
|
migration_id,
|
|
repo_id,
|
|
chunk_ordinal,
|
|
chunk_count,
|
|
chunk_digest,
|
|
..
|
|
} => AdministrativeEvidenceContextV1 {
|
|
destination_repo: *repo_id,
|
|
operation_id: legacy_migration_operation_id(
|
|
*migration_id,
|
|
*repo_id,
|
|
*chunk_ordinal,
|
|
*chunk_count,
|
|
*chunk_digest,
|
|
),
|
|
},
|
|
_ => evidence_context(),
|
|
}
|
|
}
|
|
|
|
pub fn signed_init() -> SignedInitOperationV2 {
|
|
let key = key(3);
|
|
SignedInitOperationV2::sign(
|
|
InitOperationV2 {
|
|
operation_id: [0x31; 16],
|
|
repo_id: id(2),
|
|
issued_at_micros: 1_000,
|
|
retry_until_micros: 5_000,
|
|
nonce: [0x32; 16],
|
|
genesis_len: 777,
|
|
genesis_hash: id(4),
|
|
},
|
|
&key,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
pub fn signed_normal_push() -> SignedPushOperationV2 {
|
|
let key = key(1);
|
|
SignedPushOperationV2::sign(
|
|
PushOperationV2 {
|
|
operation_id: [0x11; 16],
|
|
repo_id: id(2),
|
|
issued_at_micros: 1_000,
|
|
retry_until_micros: 5_000,
|
|
nonce: [0x12; 16],
|
|
expected_authority: id(4),
|
|
authority_update: Some(id(5)),
|
|
updates: vec![
|
|
TypedRefCas {
|
|
target: RefTarget::Branch("main".into()),
|
|
expected: Some(id(6)),
|
|
mutation: RefMutation::Set(id(7)),
|
|
force: false,
|
|
},
|
|
TypedRefCas {
|
|
target: RefTarget::Release("v0".into()),
|
|
expected: Some(id(8)),
|
|
mutation: RefMutation::Delete,
|
|
force: true,
|
|
},
|
|
],
|
|
pack_len: 128,
|
|
pack_hash: id(9),
|
|
snapshot_generation_digest: id(10),
|
|
projection_stage: None,
|
|
kind: PushKindV2::Normal,
|
|
},
|
|
&key,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
pub fn signed_fork_push() -> SignedPushOperationV2 {
|
|
let key = key(2);
|
|
SignedPushOperationV2::sign(
|
|
PushOperationV2 {
|
|
operation_id: [0x21; 16],
|
|
repo_id: id(20),
|
|
issued_at_micros: 2_000,
|
|
retry_until_micros: 8_000,
|
|
nonce: [0x22; 16],
|
|
expected_authority: id(21),
|
|
authority_update: None,
|
|
updates: vec![TypedRefCas {
|
|
target: RefTarget::Branch("main".into()),
|
|
expected: None,
|
|
mutation: RefMutation::Set(id(22)),
|
|
force: false,
|
|
}],
|
|
pack_len: 256,
|
|
pack_hash: id(23),
|
|
snapshot_generation_digest: id(24),
|
|
projection_stage: None,
|
|
kind: PushKindV2::Fork(ForkProofV2 {
|
|
source_repo_id: id(25),
|
|
source_genesis: id(26),
|
|
source_tip: id(27),
|
|
source_authority: id(28),
|
|
}),
|
|
},
|
|
&key,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
pub fn snapshot() -> SignedRepoSnapshotV1 {
|
|
let key = key(7);
|
|
SignedRepoSnapshotV1::sign(
|
|
RepoSnapshotV1 {
|
|
source_instance: key.public().0,
|
|
source_key_epoch: 9,
|
|
repo_id: id(2),
|
|
genesis_authority: id(4),
|
|
current_authority: id(5),
|
|
projection: ProjectionMode::Full,
|
|
refs: vec![
|
|
RefStateV1 {
|
|
target: RefTarget::Branch("main".into()),
|
|
object: id(7),
|
|
},
|
|
RefStateV1 {
|
|
target: RefTarget::Release("v1".into()),
|
|
object: id(8),
|
|
},
|
|
],
|
|
event_low_repo_sequence: 10,
|
|
object_low_repo_sequence: 9,
|
|
high_repo_sequence: 12,
|
|
high_event_digest: id(40),
|
|
resulting_state_digest: id(41),
|
|
config_epoch: 3,
|
|
capabilities_digest: id(42),
|
|
},
|
|
&key,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
pub fn committed_transaction() -> CommittedTransactionV1 {
|
|
CommittedTransactionV1 {
|
|
repo_id: id(2),
|
|
repo_sequence: 12,
|
|
previous_event_digest: id(39),
|
|
sequenced_at_micros: 12_345,
|
|
source_kind: SourceKindV1::Client,
|
|
actor: key(1).public().0,
|
|
operation_id: [0x11; 16],
|
|
operation_digest: signed_normal_push().stable_digest().unwrap(),
|
|
signed_evidence_digest: id(43),
|
|
old_authority: id(4),
|
|
new_authority: id(5),
|
|
refs: vec![AppliedRefV1 {
|
|
target: RefTarget::Branch("main".into()),
|
|
old: Some(id(6)),
|
|
new: Some(id(7)),
|
|
force: false,
|
|
}],
|
|
object_ids: vec![id(31), id(32), id(33)],
|
|
commit_ids: vec![id(33)],
|
|
resulting_state_digest: id(41),
|
|
}
|
|
}
|
|
|
|
pub fn signed_event() -> SignedCommittedTransactionV1 {
|
|
SignedCommittedTransactionV1::sign(committed_transaction(), 9, &key(7)).unwrap()
|
|
}
|
|
|
|
pub fn receipt() -> CommitReceiptV1 {
|
|
CommitReceiptV1 {
|
|
operation_id: [0x11; 16],
|
|
operation_digest: signed_normal_push().stable_digest().unwrap(),
|
|
repo_sequence: 12,
|
|
current_authority: id(5),
|
|
refs: vec![AppliedRefV1 {
|
|
target: RefTarget::Branch("main".into()),
|
|
old: Some(id(6)),
|
|
new: Some(id(7)),
|
|
force: false,
|
|
}],
|
|
objects_new: 3,
|
|
retry_until_micros: 5_000,
|
|
first_visible_at_micros: 4_500,
|
|
receipt_visible_until_micros: 6_500,
|
|
}
|
|
}
|
|
|
|
pub fn signed_read() -> SignedReadRequestV2 {
|
|
SignedReadRequestV2::sign(
|
|
CanonicalReadRequestV2 {
|
|
method: HttpMethodV2::Post,
|
|
route: ReadRouteV2::MissingObjects,
|
|
repo_id: id(2),
|
|
body_digest: id(70),
|
|
snapshot_token_digest: id(71),
|
|
timestamp_micros: 3_000,
|
|
nonce: [0x44; 16],
|
|
},
|
|
&key(4),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
/// One `SignedReadRequestV2` per HTTP method the typed routes use, including
|
|
/// a public (zero snapshot-token-digest) acquisition request, so the
|
|
/// method/route pairing itself is byte-frozen and not just one POST route.
|
|
pub fn signed_reads() -> Vec<SignedReadRequestV2> {
|
|
vec![
|
|
SignedReadRequestV2::sign(
|
|
CanonicalReadRequestV2 {
|
|
method: HttpMethodV2::Get,
|
|
route: ReadRouteV2::Snapshot,
|
|
repo_id: id(2),
|
|
body_digest: id(0),
|
|
snapshot_token_digest: ObjectId([0; 32]),
|
|
timestamp_micros: 2_000,
|
|
nonce: [0x43; 16],
|
|
},
|
|
&key(4),
|
|
)
|
|
.unwrap(),
|
|
SignedReadRequestV2::sign(
|
|
CanonicalReadRequestV2 {
|
|
method: HttpMethodV2::Get,
|
|
route: ReadRouteV2::Object { object_id: id(9) },
|
|
repo_id: id(2),
|
|
body_digest: id(0),
|
|
snapshot_token_digest: id(71),
|
|
timestamp_micros: 2_500,
|
|
nonce: [0x45; 16],
|
|
},
|
|
&key(4),
|
|
)
|
|
.unwrap(),
|
|
SignedReadRequestV2::sign(
|
|
CanonicalReadRequestV2 {
|
|
method: HttpMethodV2::Post,
|
|
route: ReadRouteV2::Pack,
|
|
repo_id: id(2),
|
|
body_digest: id(70),
|
|
snapshot_token_digest: id(71),
|
|
timestamp_micros: 2_600,
|
|
nonce: [0x46; 16],
|
|
},
|
|
&key(4),
|
|
)
|
|
.unwrap(),
|
|
signed_read(),
|
|
SignedReadRequestV2::sign(
|
|
CanonicalReadRequestV2 {
|
|
method: HttpMethodV2::Put,
|
|
route: ReadRouteV2::ProjectionStageChunk {
|
|
session_id: [0x61; 16],
|
|
ordinal: 0,
|
|
},
|
|
repo_id: id(2),
|
|
body_digest: id(70),
|
|
snapshot_token_digest: id(0),
|
|
timestamp_micros: 2_700,
|
|
nonce: [0x47; 16],
|
|
},
|
|
&key(4),
|
|
)
|
|
.unwrap(),
|
|
SignedReadRequestV2::sign(
|
|
CanonicalReadRequestV2 {
|
|
method: HttpMethodV2::Delete,
|
|
route: ReadRouteV2::ReleaseLease,
|
|
repo_id: id(2),
|
|
body_digest: id(0),
|
|
snapshot_token_digest: id(71),
|
|
timestamp_micros: 2_800,
|
|
nonce: [0x48; 16],
|
|
},
|
|
&key(4),
|
|
)
|
|
.unwrap(),
|
|
]
|
|
}
|
|
|
|
pub fn snapshot_lease_token() -> SnapshotLeaseTokenV1 {
|
|
let generation_digest = snapshot().snapshot.generation_digest().unwrap();
|
|
SnapshotLeaseTokenV1::mint(
|
|
SnapshotLeaseClaimsV1 {
|
|
version: SNAPSHOT_LEASE_TOKEN_VERSION,
|
|
mac_key_epoch: 3,
|
|
token_id: [0x51; 16],
|
|
repo_id: id(2),
|
|
projection: ProjectionMode::Full,
|
|
generation_digest,
|
|
high_repo_sequence: 12,
|
|
high_event_digest: id(40),
|
|
issued_at_micros: 9_000,
|
|
expires_at_micros: 10_000,
|
|
reader_key_digest: reader_key_digest_or_zero(Some(key(4).public().0)),
|
|
},
|
|
&[0xa5; 32],
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
pub fn transaction_page() -> TransactionPageV1 {
|
|
let transaction = committed_transaction();
|
|
TransactionPageV1 {
|
|
repo_id: transaction.repo_id,
|
|
after_repo_sequence: 11,
|
|
after_event_digest: id(39),
|
|
fixed_upper_repo_sequence: 12,
|
|
events: vec![signed_event()],
|
|
}
|
|
}
|
|
|
|
pub fn maintenance_cutover() -> MaintenanceCutoverV1 {
|
|
MaintenanceCutoverV1 {
|
|
storage_format_version: 2,
|
|
minimum_protocol_version: 2,
|
|
v1_post_disabled: true,
|
|
writer_set_digest: id(1),
|
|
peer_set_digest: id(2),
|
|
maintenance_generation: 1,
|
|
}
|
|
}
|
|
|
|
pub fn all_evidence() -> Vec<TransactionEvidenceV1> {
|
|
let context = evidence_context();
|
|
let admin_key = key(8);
|
|
let legacy = TransactionEvidenceV1::LegacyMigrationV1 {
|
|
actor: admin_key.public().0,
|
|
actor_key_epoch: 2,
|
|
migration_id: [0x51; 16],
|
|
repo_id: id(3),
|
|
chunk_ordinal: 1,
|
|
chunk_count: 4,
|
|
chunk_digest: id(81),
|
|
manifest_digest: id(82),
|
|
source_layout_digest: id(83),
|
|
signature: [0; 64],
|
|
};
|
|
let legacy_context = evidence_context_for(&legacy);
|
|
vec![
|
|
TransactionEvidenceV1::ClientV2 {
|
|
signed_envelope: SignedClientOperationV2::Push(signed_normal_push()),
|
|
},
|
|
TransactionEvidenceV1::ClientV2 {
|
|
signed_envelope: SignedClientOperationV2::Push(signed_fork_push()),
|
|
},
|
|
TransactionEvidenceV1::MirrorEventV1 {
|
|
source_instance: key(7).public().0,
|
|
source_key_epoch: 9,
|
|
source_snapshot_digest: snapshot().snapshot.generation_digest().unwrap(),
|
|
source_event: signed_event(),
|
|
},
|
|
TransactionEvidenceV1::MirrorSnapshotV1 {
|
|
source_instance: key(7).public().0,
|
|
source_key_epoch: 9,
|
|
source_snapshot: snapshot(),
|
|
destination_projection: ProjectionMode::Release,
|
|
projected_manifest_digest: id(80),
|
|
projected_object_count: 3,
|
|
projected_object_bytes: 2048,
|
|
},
|
|
legacy
|
|
.sign_administrative(legacy_context, &admin_key)
|
|
.unwrap(),
|
|
TransactionEvidenceV1::ProjectionAdminV1 {
|
|
actor: admin_key.public().0,
|
|
actor_key_epoch: 2,
|
|
command_digest: id(84),
|
|
previous_projection: ProjectionMode::Full,
|
|
new_projection: ProjectionMode::Metadata,
|
|
signature: [0; 64],
|
|
}
|
|
.sign_administrative(context, &admin_key)
|
|
.unwrap(),
|
|
TransactionEvidenceV1::AdministrativeV1 {
|
|
actor: admin_key.public().0,
|
|
actor_key_epoch: 2,
|
|
command_digest: id(85),
|
|
signature: [0; 64],
|
|
}
|
|
.sign_administrative(context, &admin_key)
|
|
.unwrap(),
|
|
]
|
|
}
|
|
|
|
pub fn staged_projection() -> (
|
|
ProjectionStageSessionV1,
|
|
Vec<ProjectionStageChunkV1>,
|
|
ProjectionStageManifestV1,
|
|
StagedProjectionInstallV1,
|
|
) {
|
|
let session_id = [0x61; 16];
|
|
let raw = Blob::new(b"phase-zero-staged-object".to_vec()).serialize();
|
|
let object_id = levcs_core::blake3_hash(&raw);
|
|
let descriptor = StagedObjectV1 {
|
|
object_id,
|
|
object_type: ObjectType::Blob as u8,
|
|
raw_len: raw.len() as u64,
|
|
raw_digest: object_id,
|
|
};
|
|
let chunk = ProjectionStageChunkV1 {
|
|
session_id,
|
|
ordinal: 0,
|
|
chunk_count: 1,
|
|
objects: vec![StagedChunkObjectV1 {
|
|
descriptor: descriptor.clone(),
|
|
raw_bytes: raw,
|
|
}],
|
|
};
|
|
let chunk_digest = chunk.chunk_digest().unwrap();
|
|
let manifest = ProjectionStageManifestV1 {
|
|
session_id,
|
|
chunk_digests: vec![chunk_digest],
|
|
objects: vec![descriptor.clone()],
|
|
membership_root: id(90),
|
|
};
|
|
let manifest_digest = manifest.manifest_digest().unwrap();
|
|
let session = ProjectionStageSessionV1 {
|
|
session_id,
|
|
destination_repo: id(3),
|
|
destination_genesis: id(4),
|
|
expected_authority: id(4),
|
|
projection: ProjectionMode::Full,
|
|
source_kind: StageSourceKindV1::Mirror,
|
|
actor: key(7).public().0,
|
|
actor_key_epoch: 9,
|
|
source_generation_digest: snapshot().snapshot.generation_digest().unwrap(),
|
|
fork_proof: None,
|
|
final_operation_id: [0x62; 16],
|
|
final_operation_digest: id(91),
|
|
final_evidence_digest: id(92),
|
|
total_object_count: 1,
|
|
total_object_bytes: descriptor.raw_len,
|
|
chunk_count: 1,
|
|
manifest_digest,
|
|
expires_at_micros: 100_000,
|
|
};
|
|
let install = StagedProjectionInstallV1 {
|
|
session_id,
|
|
manifest_digest,
|
|
projection: ProjectionMode::Full,
|
|
object_count: 1,
|
|
object_bytes: descriptor.raw_len,
|
|
membership_root: manifest.membership_root,
|
|
artifact_set_digest: id(93),
|
|
};
|
|
(session, vec![chunk], manifest, install)
|
|
}
|
|
|
|
pub fn roundtrip<T>(value: &T)
|
|
where
|
|
T: CanonicalCodec + std::fmt::Debug + PartialEq,
|
|
{
|
|
let encoded = value.encode_canonical().unwrap();
|
|
assert_eq!(&T::decode_canonical(&encoded).unwrap(), value);
|
|
}
|
|
|
|
pub fn golden_value() -> serde_json::Value {
|
|
let evidence = all_evidence();
|
|
let signed_snapshot = snapshot();
|
|
let committed = committed_transaction();
|
|
let receipt = receipt();
|
|
let (_, chunks, manifest, _) = staged_projection();
|
|
let blob = Blob::new(b"phase-zero-object-golden".to_vec());
|
|
let blob_bytes = blob.serialize();
|
|
let mut retry_operation = signed_normal_push().operation;
|
|
retry_operation.issued_at_micros += 10;
|
|
retry_operation.nonce = [0x99; 16];
|
|
let retry_push = SignedPushOperationV2::sign(retry_operation, &key(1)).unwrap();
|
|
let mut different_genesis_operation = signed_init().operation;
|
|
different_genesis_operation.genesis_hash = id(99);
|
|
let different_genesis =
|
|
SignedInitOperationV2::sign(different_genesis_operation, &key(3)).unwrap();
|
|
let mut pack = levcs_protocol::Pack::new();
|
|
pack.push(ObjectType::Blob as u8, b"phase-0-pack".to_vec());
|
|
|
|
let init_client_evidence = SignedClientOperationV2::Init(signed_init());
|
|
let push_body = encode_push_request_body(
|
|
&signed_normal_push(),
|
|
&vec![0xab; signed_normal_push().operation.pack_len as usize],
|
|
)
|
|
.unwrap();
|
|
let init_body = encode_init_request_body(
|
|
&signed_init(),
|
|
&vec![0xcd; signed_init().operation.genesis_len as usize],
|
|
)
|
|
.unwrap();
|
|
let (session, _, _, install) = staged_projection();
|
|
let lease_token = snapshot_lease_token();
|
|
let page = transaction_page();
|
|
let cutover = maintenance_cutover();
|
|
let reads = signed_reads();
|
|
|
|
let statuses = [
|
|
TransactionStatusV1::Pending {
|
|
operation_digest: receipt.operation_digest,
|
|
retry_until_micros: receipt.retry_until_micros,
|
|
phase: PendingPhase::Queued,
|
|
},
|
|
TransactionStatusV1::Resolving {
|
|
operation_digest: receipt.operation_digest,
|
|
retry_until_micros: receipt.retry_until_micros,
|
|
shard_sequence: Some(77),
|
|
},
|
|
TransactionStatusV1::Committed(receipt.clone()),
|
|
TransactionStatusV1::Expired {
|
|
operation_digest: receipt.operation_digest,
|
|
retry_until_micros: receipt.retry_until_micros,
|
|
tombstone_until_micros: 7_000,
|
|
},
|
|
TransactionStatusV1::Unknown,
|
|
];
|
|
|
|
serde_json::json!({
|
|
"schema_version": 1,
|
|
"objects": {
|
|
"blob_hex": hex::encode(&blob_bytes),
|
|
"blob_id": blob.object_id().to_hex(),
|
|
"pack_v1_hex": hex::encode(pack.encode())
|
|
},
|
|
"vectors": {
|
|
"init_envelope_hex": hex::encode(signed_init().encode_canonical().unwrap()),
|
|
"init_same_id_different_genesis_hex": hex::encode(different_genesis.encode_canonical().unwrap()),
|
|
"normal_push_envelope_hex": hex::encode(signed_normal_push().encode_canonical().unwrap()),
|
|
"normal_push_retry_envelope_hex": hex::encode(retry_push.encode_canonical().unwrap()),
|
|
"fork_evidence_hex": hex::encode(evidence[1].encode_canonical().unwrap()),
|
|
"mirror_event_evidence_hex": hex::encode(evidence[2].encode_canonical().unwrap()),
|
|
"mirror_snapshot_evidence_hex": hex::encode(evidence[3].encode_canonical().unwrap()),
|
|
"legacy_evidence_hex": hex::encode(evidence[4].encode_canonical().unwrap()),
|
|
"projection_admin_evidence_hex": hex::encode(evidence[5].encode_canonical().unwrap()),
|
|
"administrative_evidence_hex": hex::encode(evidence[6].encode_canonical().unwrap()),
|
|
"signed_event_hex": hex::encode(signed_event().encode_canonical().unwrap()),
|
|
"signed_snapshot_hex": hex::encode(signed_snapshot.encode_canonical().unwrap()),
|
|
"signed_private_read_hex": hex::encode(signed_read().encode_canonical().unwrap()),
|
|
"missing_request_hex": hex::encode(MissingObjectsRequestV1 {
|
|
generation_digest: id(71),
|
|
object_ids: vec![id(1), id(2), id(3)]
|
|
}.encode_canonical().unwrap()),
|
|
"stage_chunk_hex": hex::encode(chunks[0].encode_canonical().unwrap()),
|
|
"stage_manifest_hex": hex::encode(manifest.encode_canonical().unwrap()),
|
|
"init_client_evidence_hex": hex::encode(init_client_evidence.encode_canonical().unwrap()),
|
|
"push_body_hex": hex::encode(&push_body),
|
|
"init_body_hex": hex::encode(&init_body),
|
|
"stage_session_hex": hex::encode(session.encode_canonical().unwrap()),
|
|
"staged_install_hex": hex::encode(install.encode_canonical().unwrap()),
|
|
"snapshot_lease_token_hex": hex::encode(lease_token.encode_canonical().unwrap()),
|
|
"transaction_page_hex": hex::encode(page.encode_canonical().unwrap()),
|
|
"maintenance_cutover_hex": hex::encode(cutover.encode_canonical().unwrap()),
|
|
"signed_reads_hex": reads.iter().map(|r| hex::encode(r.encode_canonical().unwrap())).collect::<Vec<_>>()
|
|
},
|
|
"digests": {
|
|
"ref_state": ref_state_digest(&signed_snapshot.snapshot.refs).unwrap().to_hex(),
|
|
"snapshot_generation": signed_snapshot.snapshot.generation_digest().unwrap().to_hex(),
|
|
"event": committed.event_digest().unwrap().to_hex(),
|
|
"fork_evidence": evidence[1].evidence_digest().unwrap().to_hex(),
|
|
"mirror_event_evidence": evidence[2].evidence_digest().unwrap().to_hex(),
|
|
"mirror_snapshot_evidence": evidence[3].evidence_digest().unwrap().to_hex(),
|
|
"legacy_evidence": evidence[4].evidence_digest().unwrap().to_hex(),
|
|
"projection_admin_evidence": evidence[5].evidence_digest().unwrap().to_hex(),
|
|
"administrative_evidence": evidence[6].evidence_digest().unwrap().to_hex(),
|
|
"status_pending": statuses[0].status_digest().unwrap().to_hex(),
|
|
"status_resolving": statuses[1].status_digest().unwrap().to_hex(),
|
|
"status_committed": statuses[2].status_digest().unwrap().to_hex(),
|
|
"status_expired": statuses[3].status_digest().unwrap().to_hex(),
|
|
"status_unknown": statuses[4].status_digest().unwrap().to_hex(),
|
|
"stage_chunk": chunks[0].chunk_digest().unwrap().to_hex(),
|
|
"stage_manifest": manifest.manifest_digest().unwrap().to_hex(),
|
|
"init_stable": signed_init().stable_digest().unwrap().to_hex(),
|
|
"stage_session": session.session_digest().unwrap().to_hex()
|
|
}
|
|
})
|
|
}
|