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
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_crypto::HashValue;
use move_deps::move_core_types::{account_address::AccountAddress, value::MoveValue};
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,
    epoch: u64,
    round: u64,
    proposer: AccountAddress,
    proposer_index: Option<u32>,
    previous_block_votes: Vec<bool>,
    failed_proposer_indices: Vec<u32>,
    timestamp_usecs: u64,
}

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

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

    pub fn get_prologue_move_args(self, signer: AccountAddress) -> Vec<MoveValue> {
        vec![
            MoveValue::Signer(signer),
            MoveValue::U64(self.epoch),
            MoveValue::U64(self.round),
            MoveValue::Address(self.proposer),
            MoveValue::Vector(
                self.proposer_index
                    .map_or_else(Vec::new, |index| vec![MoveValue::U64(u64::from(index))]),
            ),
            MoveValue::Vector(
                self.failed_proposer_indices
                    .into_iter()
                    .map(u64::from)
                    .map(MoveValue::U64)
                    .collect(),
            ),
            MoveValue::Vector(
                self.previous_block_votes
                    .into_iter()
                    .map(MoveValue::Bool)
                    .collect(),
            ),
            MoveValue::U64(self.timestamp_usecs),
        ]
    }

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

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

    pub fn proposer_index(&self) -> Option<u32> {
        self.proposer_index
    }

    pub fn previous_block_votes(&self) -> &Vec<bool> {
        &self.previous_block_votes
    }

    pub fn failed_proposer_indices(&self) -> &Vec<u32> {
        &self.failed_proposer_indices
    }

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

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