Skip to content

Commit 06ab930

Browse files
committed
Added graphql block endpoint
1 parent 5c85b24 commit 06ab930

File tree

15 files changed

+287
-44
lines changed

15 files changed

+287
-44
lines changed

core/src/block/block_with_hash.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ impl<T: AsRef<Block>> BlockWithHash<T> {
149149
) -> Box<dyn 'a + Iterator<Item = &'a v2::TransactionSnarkWorkTStableV2>> {
150150
self.body().completed_works_iter()
151151
}
152+
153+
pub fn block_stake_winner(&self) -> &v2::NonZeroCurvePoint {
154+
block_stake_winner(self.header())
155+
}
152156
}
153157

154158
impl<T: AsRef<BlockHeader>> BlockHeaderWithHash<T> {
@@ -227,6 +231,10 @@ impl<T: AsRef<BlockHeader>> BlockHeaderWithHash<T> {
227231
pub fn staged_ledger_hashes(&self) -> &v2::MinaBaseStagedLedgerHashStableV1 {
228232
staged_ledger_hashes(self.header())
229233
}
234+
235+
pub fn block_stake_winner(&self) -> &v2::NonZeroCurvePoint {
236+
block_stake_winner(self.header())
237+
}
230238
}
231239

232240
fn consensus_state(
@@ -318,3 +326,11 @@ fn staged_ledger_hashes(header: &BlockHeader) -> &v2::MinaBaseStagedLedgerHashSt
318326
.blockchain_state
319327
.staged_ledger_hash
320328
}
329+
330+
fn block_stake_winner(header: &BlockHeader) -> &v2::NonZeroCurvePoint {
331+
&header
332+
.protocol_state
333+
.body
334+
.consensus_state
335+
.block_stake_winner
336+
}

node/common/src/service/rpc/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ pub mod transition_frontier;
99

1010
use node::rpc::{
1111
RpcBestChainResponse, RpcBlockProducerStatsGetResponse, RpcConsensusConstantsGetResponse,
12-
RpcDiscoveryBoostrapStatsResponse, RpcDiscoveryRoutingTableResponse, RpcHealthCheckResponse,
13-
RpcHeartbeatGetResponse, RpcLedgerAccountsResponse, RpcLedgerSlimAccountsResponse,
14-
RpcMessageProgressResponse, RpcPeersGetResponse, RpcReadinessCheckResponse, RpcRequest,
15-
RpcStateGetError, RpcStatusGetResponse, RpcTransactionInjectResponse,
16-
RpcTransactionPoolResponse, RpcTransactionStatusGetResponse,
12+
RpcDiscoveryBoostrapStatsResponse, RpcDiscoveryRoutingTableResponse, RpcGetBlockResponse,
13+
RpcHealthCheckResponse, RpcHeartbeatGetResponse, RpcLedgerAccountsResponse,
14+
RpcLedgerSlimAccountsResponse, RpcMessageProgressResponse, RpcPeersGetResponse,
15+
RpcReadinessCheckResponse, RpcRequest, RpcStateGetError, RpcStatusGetResponse,
16+
RpcTransactionInjectResponse, RpcTransactionPoolResponse, RpcTransactionStatusGetResponse,
1717
RpcTransitionFrontierUserCommandsResponse,
1818
};
1919
use serde::{Deserialize, Serialize};
@@ -308,6 +308,7 @@ impl node::rpc_effectful::RpcService for NodeService {
308308
RpcConsensusConstantsGetResponse
309309
);
310310
rpc_service_impl!(respond_transaction_status, RpcTransactionStatusGetResponse);
311+
rpc_service_impl!(respond_block_get, RpcGetBlockResponse);
311312
}
312313

313314
#[cfg(test)]

node/native/src/graphql/account.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ pub struct GraphQLVerificationKey {
118118
pub hash: String,
119119
}
120120

121+
#[derive(GraphQLObject, Debug)]
122+
/// Dummy type to represent [`GraphQLAccount`]
123+
pub struct GraphQLDummyAccount {
124+
pub public_key: String,
125+
}
126+
121127
impl From<ledger::SetVerificationKey<ledger::AuthRequired>> for GraphQLSetVerificationKey {
122128
fn from(value: ledger::SetVerificationKey<ledger::AuthRequired>) -> Self {
123129
Self {

node/native/src/graphql/block.rs

Lines changed: 149 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,73 @@
1-
use juniper::GraphQLObject;
2-
use openmina_core::block::AppliedBlock;
3-
41
use crate::graphql::zkapp::{GraphQLFailureReason, GraphQLFeePayer, GraphQLZkappCommand};
2+
use juniper::{GraphQLEnum, GraphQLObject};
3+
use mina_p2p_messages::v2::{
4+
MinaBaseSignedCommandPayloadBodyStableV2, MinaBaseStakeDelegationStableV2,
5+
TransactionSnarkWorkTStableV2,
6+
};
7+
use openmina_core::block::AppliedBlock;
58

6-
use super::{zkapp::GraphQLZkapp, ConversionError};
9+
use super::{account::GraphQLDummyAccount, zkapp::GraphQLZkapp, ConversionError};
710

811
#[derive(GraphQLObject, Debug)]
912
#[graphql(description = "A Mina block")]
10-
pub struct GraphQLBestChainBlock {
11-
pub protocol_state: GraphQLProtocolState,
13+
/// Location [src/lib/mina_graphql/types.ml:2095](https://github.com/MinaProtocol/mina/blob/develop/src/lib/mina_graphql/types.ml#L2095-L2151)
14+
pub struct GraphQLBlock {
15+
pub creator: String,
16+
/// TODO: this must be fetched separately from `AppliedBlock`
17+
pub creator_account: GraphQLDummyAccount,
18+
/// TODO: this must be fetched separately from `AppliedBlock`
19+
pub winner_account: GraphQLDummyAccount,
1220
pub state_hash: String,
21+
/// Experimental: Bigint field-element representation of stateHash
22+
pub state_hash_field: String,
23+
pub protocol_state: GraphQLProtocolState,
24+
/// Public key of account that produced this block
25+
/// use creatorAccount field instead
1326
pub transactions: GraphQLTransactions,
27+
/// Base58Check-encoded hash of the state after this block
28+
/// Count of user command transactions in the block
29+
pub command_transaction_count: i32,
30+
pub snark_jobs: Vec<GraphQLSnarkJob>,
31+
}
32+
33+
#[derive(GraphQLObject, Debug)]
34+
pub struct GraphQLSnarkJob {
35+
pub fee: String,
36+
pub prover: String,
1437
}
1538

1639
#[derive(GraphQLObject, Debug)]
1740
pub struct GraphQLTransactions {
1841
pub zkapp_commands: Vec<GraphQLZkapp>,
42+
pub user_commands: Vec<GraphQLUserCommands>,
43+
}
44+
45+
#[derive(GraphQLObject, Debug)]
46+
pub struct GraphQLUserCommands {
47+
pub amount: Option<String>,
48+
pub failure_reason: Option<String>,
49+
pub fee: String,
50+
pub fee_token: String,
51+
pub from: String,
52+
pub hash: String,
53+
pub id: String,
54+
pub is_delegation: bool,
55+
pub kind: GraphQLUserCommandsKind,
56+
pub memo: String,
57+
pub nonce: i32,
58+
pub to: String,
59+
pub token: String,
60+
pub valid_until: String,
61+
}
62+
63+
#[derive(Clone, Copy, Debug, GraphQLEnum)]
64+
#[allow(non_camel_case_types)]
65+
pub enum GraphQLUserCommandsKind {
66+
PAYMENT,
67+
STAKE_DELEGATION,
1968
}
2069

21-
impl TryFrom<AppliedBlock> for GraphQLBestChainBlock {
70+
impl TryFrom<AppliedBlock> for GraphQLBlock {
2271
type Error = ConversionError;
2372
fn try_from(value: AppliedBlock) -> Result<Self, Self::Error> {
2473
let block = value.block;
@@ -58,10 +107,28 @@ impl TryFrom<AppliedBlock> for GraphQLBestChainBlock {
58107
.into(),
59108
};
60109

110+
let command_transaction_count = block.body().diff().0.commands.len() as i32;
111+
112+
let snark_jobs = block
113+
.body()
114+
.completed_works_iter()
115+
.map(GraphQLSnarkJob::from)
116+
.collect();
117+
61118
Ok(Self {
119+
creator_account: GraphQLDummyAccount {
120+
public_key: block.producer().to_string(),
121+
},
122+
winner_account: GraphQLDummyAccount {
123+
public_key: block.block_stake_winner().to_string(),
124+
},
62125
protocol_state,
63126
state_hash: block.hash.to_string(),
127+
state_hash_field: block.hash.to_decimal(),
128+
creator: block.producer().to_string(),
64129
transactions: block.body().diff().clone().try_into()?,
130+
command_transaction_count,
131+
snark_jobs,
65132
})
66133
}
67134
}
@@ -123,25 +190,66 @@ impl TryFrom<mina_p2p_messages::v2::StagedLedgerDiffDiffDiffStableV2> for GraphQ
123190
.1
124191
.map_or_else(Vec::new, |v| v.commands.into_iter().collect::<Vec<_>>());
125192

126-
let zkapp_commands = value
193+
let commands = value
127194
.0
128195
.commands
129196
.into_iter()
130197
.chain(also_zkapp_commands)
131-
.rev()
132-
.map(|cmd| {
133-
// std::fs::create_dir_all("zkapps").unwrap();
134-
// let zkapp_path = format!("zkapps/{}", zkapp.hash().unwrap());
135-
// let path = PathBuf::from(zkapp_path.clone());
136-
// if !path.exists() {
137-
// let mut buff = Vec::new();
138-
// zkapp.binprot_write(&mut buff).unwrap();
139-
// std::fs::write(zkapp_path, buff).unwrap();
140-
// }
141-
if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp) = cmd.data {
198+
.rev();
199+
200+
let mut zkapp_commands = Vec::new();
201+
let mut user_commands = Vec::new();
202+
203+
for command in commands {
204+
match command.data {
205+
MinaBaseUserCommandStableV2::SignedCommand(user_command) => {
206+
let is_delegation = matches!(
207+
user_command.payload.body,
208+
MinaBaseSignedCommandPayloadBodyStableV2::StakeDelegation(_)
209+
);
210+
let hash = user_command.hash()?.to_string();
211+
212+
let fee = user_command.payload.common.fee.to_string();
213+
let memo = user_command.payload.common.memo.to_base58check();
214+
let nonce = user_command.payload.common.nonce.as_u32() as i32;
215+
let valid_until = user_command.payload.common.valid_until.as_u32().to_string();
216+
217+
let (to, amount, kind) = match user_command.payload.body {
218+
MinaBaseSignedCommandPayloadBodyStableV2::Payment(payment) => (
219+
payment.receiver_pk.to_string(),
220+
Some(payment.amount.to_string()),
221+
GraphQLUserCommandsKind::PAYMENT,
222+
),
223+
MinaBaseSignedCommandPayloadBodyStableV2::StakeDelegation(
224+
MinaBaseStakeDelegationStableV2::SetDelegate { new_delegate },
225+
) => (
226+
new_delegate.to_string(),
227+
None,
228+
GraphQLUserCommandsKind::STAKE_DELEGATION,
229+
),
230+
};
231+
232+
user_commands.push(GraphQLUserCommands {
233+
hash,
234+
from: user_command.signer.to_string(),
235+
to,
236+
is_delegation,
237+
amount,
238+
failure_reason: Default::default(),
239+
fee,
240+
fee_token: Default::default(),
241+
id: Default::default(),
242+
kind,
243+
memo,
244+
nonce,
245+
token: Default::default(),
246+
valid_until,
247+
});
248+
}
249+
MinaBaseUserCommandStableV2::ZkappCommand(zkapp) => {
142250
let failure_reason =
143251
if let MinaBaseTransactionStatusStableV2::Failed(failure_collection) =
144-
cmd.status
252+
command.status
145253
{
146254
let res = failure_collection
147255
.0
@@ -158,17 +266,20 @@ impl TryFrom<mina_p2p_messages::v2::StagedLedgerDiffDiffDiffStableV2> for GraphQ
158266
})
159267
.rev()
160268
.collect();
269+
161270
Some(res)
162271
} else {
163272
None
164273
};
274+
165275
let account_updates = zkapp
166276
.account_updates
167277
.clone()
168278
.into_iter()
169279
.map(|v| v.elt.account_update.try_into())
170280
.collect::<Result<Vec<_>, _>>()?;
171-
Ok(Some(GraphQLZkapp {
281+
282+
zkapp_commands.push(GraphQLZkapp {
172283
hash: zkapp.hash()?.to_string(),
173284
failure_reason,
174285
id: zkapp.to_base64()?,
@@ -177,16 +288,15 @@ impl TryFrom<mina_p2p_messages::v2::StagedLedgerDiffDiffDiffStableV2> for GraphQ
177288
account_updates,
178289
fee_payer: GraphQLFeePayer::from(zkapp.fee_payer),
179290
},
180-
}))
181-
} else {
182-
Ok(None)
291+
});
183292
}
184-
})
185-
.collect::<Result<Vec<_>, Self::Error>>()?
186-
.into_iter()
187-
.flatten()
188-
.collect::<Vec<_>>();
189-
Ok(Self { zkapp_commands })
293+
}
294+
}
295+
296+
Ok(Self {
297+
zkapp_commands,
298+
user_commands,
299+
})
190300
}
191301
}
192302

@@ -258,3 +368,12 @@ impl From<mina_p2p_messages::v2::ConsensusProofOfStakeDataConsensusStateValueSta
258368
}
259369
}
260370
}
371+
372+
impl From<&TransactionSnarkWorkTStableV2> for GraphQLSnarkJob {
373+
fn from(value: &TransactionSnarkWorkTStableV2) -> Self {
374+
Self {
375+
fee: value.fee.to_string(),
376+
prover: value.prover.to_string(),
377+
}
378+
}
379+
}

0 commit comments

Comments
 (0)