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
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

// Copyright 2021 Conflux Foundation. All rights reserved.
// Conflux is free software and distributed under GNU General Public License.
// See http://www.gnu.org/licenses/

use crate::{
    account_address::AccountAddress,
    account_config::diem_root_address,
    event::{EventHandle, EventKey},
};
use diem_crypto::HashValue;
use move_core_types::move_resource::MoveResource;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};

/// Struct that will be persisted on chain to store the information of the
/// current block.
///
/// The flow will look like following:
/// 1. The executor will pass this struct to VM at the end of a block proposal.
/// 2. The VM will use this struct to create a special system transaction that
/// will emit an event    represents the information of the current block. This
/// transaction can't    be emitted by regular users and is generated by each of
/// the validators on the fly. Such    transaction will be executed before all
/// of the user-submitted transactions in the blocks. 3. Once that special
/// resource is modified, the other user transactions can read the consensus
///    info by calling into the read method of that resource, which would thus
/// give users the    information such as the current leader.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BlockMetadata {
    id: HashValue,
    round: u64,
    timestamp_usecs: u64,
    // The vector has to be sorted to ensure consistent result among all nodes
    previous_block_votes: Vec<AccountAddress>,
    proposer: AccountAddress,
}

impl BlockMetadata {
    pub fn new(
        id: HashValue, round: u64, timestamp_usecs: u64,
        previous_block_votes: Vec<AccountAddress>, proposer: AccountAddress,
    ) -> Self {
        Self {
            id,
            round,
            timestamp_usecs,
            previous_block_votes,
            proposer,
        }
    }

    pub fn id(&self) -> HashValue { self.id }

    pub fn into_inner(self) -> (u64, u64, Vec<AccountAddress>, AccountAddress) {
        (
            self.round,
            self.timestamp_usecs,
            self.previous_block_votes.clone(),
            self.proposer,
        )
    }

    pub fn timestamp_usec(&self) -> u64 { self.timestamp_usecs }

    pub fn proposer(&self) -> AccountAddress { self.proposer }
}

pub fn new_block_event_key() -> EventKey {
    EventKey::new_from_address(&diem_root_address(), 17)
}

/// The path to the new block event handle under a DiemBlock::BlockMetadata
/// resource.
pub static NEW_BLOCK_EVENT_PATH: Lazy<Vec<u8>> = Lazy::new(|| {
    let mut path = DiemBlockResource::resource_path();
    // it can be anything as long as it's referenced in
    // AccountState::get_event_handle_by_query_path
    path.extend_from_slice(b"/new_block_event/");
    path
});

#[derive(Deserialize, Serialize)]
pub struct DiemBlockResource {
    height: u64,
    new_block_events: EventHandle,
}

impl DiemBlockResource {
    pub fn new_block_events(&self) -> &EventHandle { &self.new_block_events }
}

impl MoveResource for DiemBlockResource {
    const MODULE_NAME: &'static str = "DiemBlock";
    const STRUCT_NAME: &'static str = "BlockMetadata";
}

#[derive(Clone, Deserialize, Serialize)]
pub struct NewBlockEvent {
    round: u64,
    proposer: AccountAddress,
    votes: Vec<AccountAddress>,
    timestamp: u64,
}

impl NewBlockEvent {
    pub fn new(
        round: u64, proposer: AccountAddress, votes: Vec<AccountAddress>,
        timestamp: u64,
    ) -> Self {
        Self {
            round,
            proposer,
            votes,
            timestamp,
        }
    }

    pub fn round(&self) -> u64 { self.round }

    pub fn proposer(&self) -> AccountAddress { self.proposer }

    pub fn votes(&self) -> Vec<AccountAddress> { self.votes.clone() }
}