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
138
139
use anyhow::{bail, Result};
use diem_types::{
account_config,
transaction::{SignedTransaction, TransactionPayload},
};
use diem_vm::system_module_names::{SCRIPT_PROLOGUE_NAME, USER_EPILOGUE_NAME};
use move_core_types::{
ident_str,
identifier::IdentStr,
language_storage::{ResourceKey, StructTag},
resolver::MoveResolver,
value::{serialize_values, MoveValue},
};
use std::ops::Deref;
pub struct ReadWriteSetAnalysis(read_write_set::ReadWriteSetAnalysis);
const TRANSACTION_FEES_NAME: &IdentStr = ident_str!("TransactionFee");
impl ReadWriteSetAnalysis {
pub fn new(rw: read_write_set::ReadWriteSetAnalysis) -> Self {
ReadWriteSetAnalysis(rw)
}
pub fn get_keys_written(
&self,
tx: &SignedTransaction,
blockchain_view: &impl MoveResolver,
) -> Result<Vec<ResourceKey>> {
self.get_concretized_keys_tx(tx, blockchain_view, true)
}
pub fn get_keys_read(
&self,
tx: &SignedTransaction,
blockchain_view: &impl MoveResolver,
) -> Result<Vec<ResourceKey>> {
self.get_concretized_keys_tx(tx, blockchain_view, false)
}
fn get_concretized_keys_tx(
&self,
tx: &SignedTransaction,
blockchain_view: &impl MoveResolver,
is_write: bool,
) -> Result<Vec<ResourceKey>> {
match tx.payload() {
TransactionPayload::ScriptFunction(s) => {
let signers = vec![tx.sender()];
let gas_currency = account_config::type_tag_for_currency_code(
account_config::from_currency_code_string(tx.gas_currency_code())?,
);
let prologue_accesses = self.get_concretized_keys(
&account_config::constants::ACCOUNT_MODULE,
SCRIPT_PROLOGUE_NAME,
&signers,
&serialize_values(&vec![
MoveValue::U64(tx.sequence_number()),
MoveValue::vector_u8(tx.authenticator().sender().public_key_bytes()),
MoveValue::U64(tx.gas_unit_price()),
MoveValue::U64(tx.max_gas_amount()),
MoveValue::U64(tx.expiration_timestamp_secs()),
MoveValue::U8(tx.chain_id().id()),
MoveValue::vector_u8(vec![]), ]),
&[gas_currency.clone()],
blockchain_view,
is_write,
)?;
let epilogue_accesses = self.get_concretized_keys(
&account_config::constants::ACCOUNT_MODULE,
USER_EPILOGUE_NAME,
&signers,
&serialize_values(&vec![
MoveValue::U64(tx.sequence_number()),
MoveValue::U64(tx.gas_unit_price()),
MoveValue::U64(tx.max_gas_amount()),
MoveValue::U64(0), ]),
&[gas_currency.clone()],
blockchain_view,
is_write,
)?;
let mut script_accesses = self.get_concretized_keys(
s.module(),
s.function(),
&signers,
s.args(),
s.ty_args(),
blockchain_view,
is_write,
)?;
if tx.gas_unit_price() == 0 {
let tx_fees_tag = StructTag {
address: account_config::CORE_CODE_ADDRESS,
module: TRANSACTION_FEES_NAME.to_owned(),
name: TRANSACTION_FEES_NAME.to_owned(),
type_params: vec![gas_currency],
};
script_accesses.retain(|r| r.type_() != &tx_fees_tag);
}
script_accesses.extend(prologue_accesses);
script_accesses.extend(epilogue_accesses);
script_accesses.sort();
script_accesses.dedup();
Ok(script_accesses)
}
payload => {
bail!("Unsupported transaction payload type {:?}", payload)
}
}
}
}
impl Deref for ReadWriteSetAnalysis {
type Target = read_write_set::ReadWriteSetAnalysis;
fn deref(&self) -> &Self::Target {
&self.0
}
}