1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use crate::rpc::types::{
    pos::{Decision, EpochState},
    Bytes,
};
use bls_signatures::{self, Serialize as BlsSerialize};
use cfx_types::{H256, U64};
use diem_crypto::ValidCryptoMaterial;
use diem_types::{
    block_info::BlockInfo as PrimitiveBlockInfo,
    ledger_info::{
        LedgerInfo as PrimitiveLedgerInfo,
        LedgerInfoWithSignatures as PrimitiveLedgerInfoWithSignatures,
    },
};
use serde::Serialize;
use std::collections::BTreeMap;

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LedgerInfoWithSignatures {
    ledger_info: LedgerInfo,
    /// The validator is identified by its account address: in order to verify
    /// a signature one needs to retrieve the public key of the validator
    /// for the given epoch.
    ///
    /// Value is uncompressed BLS signature in 192 bytes.
    signatures: BTreeMap<H256, Bytes>,
    /// Validators with uncompressed BLS public key (in 96 bytes) if next epoch
    /// state available. Generally, this is used to verify BLS signatures
    /// at client side.
    next_epoch_validators: Option<BTreeMap<H256, Bytes>>,
    /// Aggregated signature
    aggregated_signature: Bytes,
}

impl From<&PrimitiveLedgerInfoWithSignatures> for LedgerInfoWithSignatures {
    fn from(value: &PrimitiveLedgerInfoWithSignatures) -> Self {
        let signature_list: Vec<_> = value
            .signatures()
            .values()
            .map(|v| v.clone().raw())
            .collect();
        let multi_sig = bls_signatures::aggregate(&signature_list)
            .expect("only valid signatures");
        Self {
            ledger_info: value.ledger_info().into(),
            signatures: value
                .signatures()
                .iter()
                .map(|(k, v)| (H256::from(k.to_u8()), v.to_bytes().into()))
                .collect(),
            next_epoch_validators: value.ledger_info().next_epoch_state().map(
                |state| {
                    state
                        .verifier()
                        .address_to_validator_info()
                        .iter()
                        .map(|(k, v)| {
                            (
                                H256::from(k.to_u8()),
                                v.public_key()
                                    .clone()
                                    .raw()
                                    .as_affine()
                                    .to_uncompressed()
                                    .to_vec()
                                    .into(),
                            )
                        })
                        .collect()
                },
            ),
            aggregated_signature: multi_sig.as_bytes().into(),
        }
    }
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LedgerInfo {
    commit_info: BlockInfo,

    /// Hash of consensus specific data that is opaque to all parts of the
    /// system other than consensus.
    consensus_data_hash: H256,
}

impl From<&PrimitiveLedgerInfo> for LedgerInfo {
    fn from(value: &PrimitiveLedgerInfo) -> Self {
        Self {
            commit_info: value.commit_info().into(),
            consensus_data_hash: H256::from(
                value.consensus_data_hash().as_ref(),
            ),
        }
    }
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockInfo {
    /// Epoch number corresponds to the set of validators that are active for
    /// this block.
    epoch: U64,
    /// The consensus protocol is executed in rounds, which monotonically
    /// increase per epoch.
    round: U64,
    /// The identifier (hash) of the block.
    id: H256,
    /// The accumulator root hash after executing this block.
    executed_state_id: H256,
    /// The version of the latest transaction after executing this block.
    version: U64,
    /// The timestamp this block was proposed by a proposer.
    timestamp_usecs: U64,
    /// An optional field containing the next epoch info
    next_epoch_state: Option<EpochState>,
    /// TODO(lpl): Remove Option?
    /// The last pivot block selection after executing this block.
    /// None means choosing TreeGraph genesis as the first pivot block.
    pivot: Option<Decision>,
}

impl From<&PrimitiveBlockInfo> for BlockInfo {
    fn from(value: &PrimitiveBlockInfo) -> Self {
        Self {
            epoch: value.epoch().into(),
            round: value.round().into(),
            id: H256::from(value.id().as_ref()),
            executed_state_id: H256::from(value.executed_state_id().as_ref()),
            version: value.version().into(),
            timestamp_usecs: value.timestamp_usecs().into(),
            next_epoch_state: value.next_epoch_state().map(|e| e.into()),
            pivot: value.pivot_decision().map(Into::into),
        }
    }
}