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
use crate::{config::global::Config as GlobalConfig, errors::*};
use diem_crypto::HashValue;
use diem_types::{account_address::AccountAddress, block_metadata::BlockMetadata};
use std::str::FromStr;
#[derive(Debug)]
pub enum Proposer {
Account(String),
Address(AccountAddress),
}
#[derive(Debug)]
pub enum Entry {
Proposer(Proposer),
Timestamp(u64),
}
impl FromStr for Entry {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let s = s.split_whitespace().collect::<String>();
let s = &s
.strip_prefix("//!")
.ok_or_else(|| ErrorKind::Other("txn config entry must start with //!".to_string()))?
.trim_start();
if let Some(s) = s.strip_prefix("proposer:") {
if s.is_empty() {
return Err(ErrorKind::Other("sender cannot be empty".to_string()).into());
}
return Ok(Entry::Proposer(Proposer::Account(s.to_string())));
}
if let Some(s) = s.strip_prefix("proposer-address:") {
if s.is_empty() {
return Err(ErrorKind::Other("sender address cannot be empty".to_string()).into());
}
return Ok(Entry::Proposer(Proposer::Address(
AccountAddress::from_hex_literal(s)?,
)));
}
if let Some(s) = s.strip_prefix("block-time:") {
return Ok(Entry::Timestamp(s.parse::<u64>()?));
}
Err(ErrorKind::Other(format!(
"failed to parse '{}' as transaction config entry",
s
))
.into())
}
}
pub fn is_new_block(s: &str) -> bool {
let s = s.trim();
if !s.starts_with("//!") {
return false;
}
s[3..].trim_start() == "block-prologue"
}
impl Entry {
pub fn try_parse(s: &str) -> Result<Option<Self>> {
if s.starts_with("//!") {
Ok(Some(s.parse::<Entry>()?))
} else {
Ok(None)
}
}
}
pub fn build_block_metadata(config: &GlobalConfig, entries: &[Entry]) -> Result<BlockMetadata> {
let mut timestamp = None;
let mut proposer = None;
for entry in entries {
match entry {
Entry::Proposer(s) => {
proposer = match s {
Proposer::Account(s) => Some(*config.get_account_for_name(s)?.address()),
Proposer::Address(addr) => Some(*addr),
};
}
Entry::Timestamp(new_timestamp) => timestamp = Some(new_timestamp),
}
}
if let (Some(t), Some(addr)) = (timestamp, proposer) {
Ok(BlockMetadata::new(HashValue::zero(), 0, *t, vec![], addr))
} else {
Err(ErrorKind::Other("Cannot generate block metadata".to_string()).into())
}
}