1use cfx_types::{H256, U64};
6use diem_types::{
7 transaction::{ConflictSignature, TransactionPayload, TransactionStatus},
8 vm_status::KeptVMStatus,
9};
10use rustc_hex::ToHex;
11use serde::{ser::SerializeStruct, Serialize, Serializer};
12
13#[derive(Debug, Clone)]
14pub struct Transaction {
15 pub hash: H256,
16 pub from: H256,
17 pub block_hash: Option<H256>,
18 pub block_number: Option<U64>,
19 pub timestamp: Option<U64>,
20 pub number: U64,
21 pub payload: Option<RpcTransactionPayload>,
22 pub status: Option<RpcTransactionStatus>,
23 pub tx_type: RpcTransactionType,
24}
25
26#[derive(Debug, Serialize, Clone, Copy)]
27pub enum RpcTransactionStatus {
28 Executed,
29 Failed,
30 Discard,
31}
32
33#[derive(Debug, Serialize, Clone, Copy)]
34pub enum RpcTransactionType {
35 BlockMetadata,
36 Election,
37 Retire,
38 Register,
39 UpdateVotingPower,
40 PivotDecision,
41 Dispute,
42 Other,
43}
44
45#[derive(Debug, Clone)]
46pub enum RpcTransactionPayload {
47 Register(RegisterPayload),
49 Election(ElectionPayload),
51 UpdateVotingPower(UpdateVotingPowerPayload),
53 PivotDecision(PivotDecisionPayload),
55 Retire(RetirePayload),
57 Dispute(DisputePayload),
59 Other,
61}
62
63impl From<TransactionPayload> for RpcTransactionPayload {
64 fn from(payload: TransactionPayload) -> Self {
65 match payload {
66 TransactionPayload::Election(e) => {
67 RpcTransactionPayload::Election(ElectionPayload {
68 public_key: format!("0x{}", e.public_key),
69 target_term: U64::from(e.target_term),
70 vrf_proof: format!("0x{}", e.vrf_proof),
71 vrf_public_key: format!("0x{}", e.vrf_public_key),
72 })
73 }
74 TransactionPayload::Retire(r) => {
75 RpcTransactionPayload::Retire(RetirePayload {
76 address: H256::from(r.node_id.to_u8()),
77 voting_power: U64::from(r.votes),
78 })
79 }
80 TransactionPayload::Register(r) => {
81 RpcTransactionPayload::Register(RegisterPayload {
82 vrf_public_key: format!("0x{}", r.vrf_public_key),
83 public_key: format!("0x{}", r.public_key),
84 })
85 }
86 TransactionPayload::UpdateVotingPower(u) => {
87 RpcTransactionPayload::UpdateVotingPower(
88 UpdateVotingPowerPayload {
89 address: H256::from(u.node_address.to_u8()),
90 voting_power: U64::from(u.voting_power),
91 },
92 )
93 }
94 TransactionPayload::PivotDecision(p) => {
95 RpcTransactionPayload::PivotDecision(PivotDecisionPayload {
96 height: U64::from(p.height),
97 block_hash: H256::from(p.block_hash),
98 })
99 }
100 TransactionPayload::Dispute(d) => {
101 let conflicting_votes = match d.conflicting_votes {
102 ConflictSignature::Proposal((first, second)) => {
103 ConflictingVotes {
104 conflict_vote_type: "proposal".into(),
105 first: format!("0x{}", first.to_hex::<String>()),
106 second: format!("0x{}", second.to_hex::<String>()),
107 }
108 }
109 ConflictSignature::Vote((first, second)) => {
110 ConflictingVotes {
111 conflict_vote_type: "vote".into(),
112 first: format!("0x{}", first.to_hex::<String>()),
113 second: format!("0x{}", second.to_hex::<String>()),
114 }
115 }
116 };
117 RpcTransactionPayload::Dispute(DisputePayload {
118 address: H256::from(d.address.to_u8()),
119 bls_public_key: format!("0x{}", d.bls_pub_key),
120 vrf_public_key: format!("0x{}", d.vrf_pub_key),
121 conflicting_votes,
122 })
123 }
124 _ => RpcTransactionPayload::Other,
125 }
126 }
127}
128
129#[derive(Debug, Serialize, Clone)]
130#[serde(rename_all = "camelCase")]
131pub struct RegisterPayload {
132 pub vrf_public_key: String,
133 pub public_key: String,
134}
135
136#[derive(Debug, Serialize, Clone)]
137#[serde(rename_all = "camelCase")]
138pub struct ElectionPayload {
139 pub public_key: String,
140 pub target_term: U64,
141 pub vrf_proof: String,
142 pub vrf_public_key: String,
143}
144
145#[derive(Debug, Serialize, Clone)]
146#[serde(rename_all = "camelCase")]
147pub struct UpdateVotingPowerPayload {
148 pub address: H256,
149 pub voting_power: U64,
150}
151
152#[derive(Debug, Serialize, Clone)]
153#[serde(rename_all = "camelCase")]
154pub struct PivotDecisionPayload {
155 pub height: U64,
156 pub block_hash: H256,
157}
158
159#[derive(Debug, Serialize, Clone)]
160#[serde(rename_all = "camelCase")]
161pub struct RetirePayload {
162 pub address: H256,
163 pub voting_power: U64,
164}
165
166#[derive(Debug, Serialize, Clone)]
167#[serde(rename_all = "camelCase")]
168pub struct DisputePayload {
169 pub address: H256,
170 pub bls_public_key: String,
171 pub vrf_public_key: String,
172 pub conflicting_votes: ConflictingVotes,
173}
174
175#[derive(Debug, Serialize, Clone)]
176#[serde(rename_all = "camelCase")]
177pub struct ConflictingVotes {
178 pub conflict_vote_type: String,
179 pub first: String,
180 pub second: String,
181}
182
183impl Serialize for Transaction {
184 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
185 where S: Serializer {
186 let mut struc = serializer.serialize_struct("Transaction", 9)?;
187 struc.serialize_field("hash", &self.hash)?;
188 struc.serialize_field("from", &self.from)?;
189 struc.serialize_field("number", &self.number)?;
190 struc.serialize_field("blockHash", &self.block_hash)?;
191 struc.serialize_field("blockNumber", &self.block_number)?;
192 struc.serialize_field("timestamp", &self.timestamp)?;
193 struc.serialize_field("status", &self.status)?;
194 struc.serialize_field("type", &self.tx_type)?;
195 if self.payload.is_some() {
196 match &self.payload.as_ref().unwrap() {
197 RpcTransactionPayload::Election(e) => {
198 struc.serialize_field("payload", e)?;
199 }
200 RpcTransactionPayload::Retire(r) => {
201 struc.serialize_field("payload", r)?;
202 }
203 RpcTransactionPayload::Register(r) => {
204 struc.serialize_field("payload", r)?;
205 }
206 RpcTransactionPayload::UpdateVotingPower(u) => {
207 struc.serialize_field("payload", u)?;
208 }
209 RpcTransactionPayload::PivotDecision(p) => {
210 struc.serialize_field("payload", p)?;
211 }
212 RpcTransactionPayload::Dispute(d) => {
213 struc.serialize_field("payload", d)?;
214 }
215 _ => {}
216 }
217 } else {
218 let empty: Option<TransactionPayload> = None;
219 struc.serialize_field("payload", &empty)?
220 }
221 struc.end()
222 }
223}
224
225pub fn tx_type(payload: TransactionPayload) -> RpcTransactionType {
226 match payload {
227 TransactionPayload::Election(_) => RpcTransactionType::Election,
228 TransactionPayload::Retire(_) => RpcTransactionType::Retire,
229 TransactionPayload::Register(_) => RpcTransactionType::Register,
230 TransactionPayload::UpdateVotingPower(_) => {
231 RpcTransactionType::UpdateVotingPower
232 }
233 TransactionPayload::PivotDecision(_) => {
234 RpcTransactionType::PivotDecision
235 }
236 TransactionPayload::Dispute(_) => RpcTransactionType::Dispute,
237 _ => RpcTransactionType::Other,
238 }
239}
240
241impl From<TransactionStatus> for RpcTransactionStatus {
242 fn from(status: TransactionStatus) -> Self {
243 match status {
244 TransactionStatus::Discard(_) => RpcTransactionStatus::Discard,
245 TransactionStatus::Keep(keep_status) => match keep_status {
246 KeptVMStatus::Executed => RpcTransactionStatus::Executed,
247 _ => RpcTransactionStatus::Failed,
248 },
249 TransactionStatus::Retry => RpcTransactionStatus::Failed,
250 }
251 }
252}
253
254impl From<KeptVMStatus> for RpcTransactionStatus {
255 fn from(status: KeptVMStatus) -> Self {
256 match status {
257 KeptVMStatus::Executed => RpcTransactionStatus::Executed,
258 _ => RpcTransactionStatus::Failed,
259 }
260 }
261}