diff --git a/pallas-network/src/miniprotocols/localstate/queries_v16/codec.rs b/pallas-network/src/miniprotocols/localstate/queries_v16/codec.rs index 64fb811..0350faa 100644 --- a/pallas-network/src/miniprotocols/localstate/queries_v16/codec.rs +++ b/pallas-network/src/miniprotocols/localstate/queries_v16/codec.rs @@ -136,7 +136,7 @@ impl<'b> Decode<'b, ()> for BlockQuery { 4 => Ok(Self::GetProposedPParamsUpdates), 5 => Ok(Self::GetStakeDistribution), 6 => Ok(Self::GetUTxOByAddress(d.decode()?)), - // 7 => Ok(Self::GetUTxOWhole), + 7 => Ok(Self::GetUTxOWhole), // 8 => Ok(Self::DebugEpochState), 9 => Ok(Self::GetCBOR(d.decode()?)), 10 => Ok(Self::GetFilteredDelegationsAndRewardAccounts(d.decode()?)), diff --git a/pallas-network/src/miniprotocols/localstate/queries_v16/mod.rs b/pallas-network/src/miniprotocols/localstate/queries_v16/mod.rs index 76173b7..cce8af8 100644 --- a/pallas-network/src/miniprotocols/localstate/queries_v16/mod.rs +++ b/pallas-network/src/miniprotocols/localstate/queries_v16/mod.rs @@ -313,6 +313,8 @@ pub struct UTxOByAddress { pub type UTxOByTxin = UTxOByAddress; +pub type UTxOWhole = UTxOByAddress; + // Bytes CDDL -> #6.121([ * #6.121([ *datum ]) ]) pub type Datum = (Era, TagWrap); @@ -608,3 +610,13 @@ pub async fn get_utxo_by_txin( Ok(result) } + +/// Get the /entire/ UTxO. +pub async fn get_utxo_whole(client: &mut Client, era: u16) -> Result { + let query = BlockQuery::GetUTxOWhole; + let query = LedgerQuery::BlockQuery(era, query); + let query = Request::LedgerQuery(query); + let result = client.query(query).await?; + + Ok(result) +} diff --git a/pallas-network/tests/protocols.rs b/pallas-network/tests/protocols.rs index b9e676a..a7064c4 100644 --- a/pallas-network/tests/protocols.rs +++ b/pallas-network/tests/protocols.rs @@ -645,6 +645,79 @@ pub async fn local_state_query_server_and_client_happy_path() { // server receives query from client + let query: Vec = match server.statequery().recv_while_acquired().await.unwrap() { + ClientQueryRequest::Query(q) => q.unwrap(), + x => panic!( + "(While expecting `GetUTxOWhole`) \ + Unexpected message from client: {x:?}" + ), + }; + + // CBOR got from preprod node. Mind the stripped `8203`. + let cbor_query = Vec::::from_hex("8200820082068107").unwrap(); + + assert_eq!(query, cbor_query); + assert_eq!(*server.statequery().state(), localstate::State::Querying); + + let tx_hex = "1610F289E36C9D83C464F85A0AADD59101DDDB0E89592A92809D95D68D79EED9"; + let txbytes: [u8; 32] = hex::decode(tx_hex).unwrap().try_into().unwrap(); + let transaction_id_1 = Hash::from(txbytes); + let index_1 = AnyUInt::MajorByte(2); + let lovelace = AnyUInt::U32(12_419_537); + let values_1 = localstate::queries_v16::TransactionOutput::Legacy( + localstate::queries_v16::LegacyTransactionOutput { + address: Bytes::from( + hex::decode("60C0359EBB7D0688D79064BD118C99C8B87B5853E3AF59245BB97E84D2") + .unwrap(), + ), + amount: Value::Coin(lovelace), + datum_hash: None, + }, + ); + + let tx_hex = "A7BED2F5FCD72BA4CEFDA7C2CC94D119279A17D71BFFC4D90DD4272B93E8A88F"; + let txbytes: [u8; 32] = hex::decode(tx_hex).unwrap().try_into().unwrap(); + let transaction_id_2 = Hash::from(txbytes); + let index_2 = AnyUInt::MajorByte(0); + let lovelace = AnyUInt::U32(1_792_960); + let hex_datum = "D8799FD8799F1AE06755BBFF1B00000193B36BC9F0FF"; + let datum = hex::decode(hex_datum).unwrap().into(); + let tag = TagWrap::<_, 24>::new(datum); + let inline_datum = Some((1_u16, tag)); + let values_2 = localstate::queries_v16::TransactionOutput::Current( + localstate::queries_v16::PostAlonsoTransactionOutput { + address: Bytes::from( + hex::decode("603F2728EC78EF8B0F356E91A5662FF3124ADD324A7B7F5AEED69362F4") + .unwrap(), + ), + amount: Value::Coin(lovelace), + inline_datum, + script_ref: None, + }, + ); + + let utxos = KeyValuePairs::from(vec![ + ( + localstate::queries_v16::UTxO { + transaction_id: transaction_id_1, + index: index_1, + }, + values_1, + ), + ( + localstate::queries_v16::UTxO { + transaction_id: transaction_id_2, + index: index_2, + }, + values_2, + ), + ]); + + let result = AnyCbor::from_encode(localstate::queries_v16::UTxOWhole { utxo: utxos }); + server.statequery().send_result(result).await.unwrap(); + + // server receives query from client + let query: queries_v16::Request = match server.statequery().recv_while_acquired().await.unwrap() { ClientQueryRequest::Query(q) => q.into_decode().unwrap(), @@ -1001,6 +1074,33 @@ pub async fn local_state_query_server_and_client_happy_path() { assert_eq!(result, queries_v16::UTxOByAddress { utxo }); + let request = AnyCbor::from_encode(localstate::queries_v16::Request::LedgerQuery( + localstate::queries_v16::LedgerQuery::BlockQuery( + 6, + localstate::queries_v16::BlockQuery::GetUTxOWhole, + ), + )); + client.statequery().send_query(request).await.unwrap(); + + let result: Vec = client + .statequery() + .recv_while_querying() + .await + .unwrap() + .unwrap(); + + let utxo = Vec::::from_hex( + "81A28258201610F289E36C9D83C464F85A0AADD59101DDDB0E89592A92809D95D6\ + 8D79EED90282581D60C0359EBB7D0688D79064BD118C99C8B87B5853E3AF59245B\ + B97E84D21A00BD81D1825820A7BED2F5FCD72BA4CEFDA7C2CC94D119279A17D71B\ + FFC4D90DD4272B93E8A88F00A300581D603F2728EC78EF8B0F356E91A5662FF312\ + 4ADD324A7B7F5AEED69362F4011A001B5BC0028201D81856D8799FD8799F1AE067\ + 55BBFF1B00000193B36BC9F0FF", + ) + .unwrap(); + + assert_eq!(result, utxo); + let request = AnyCbor::from_encode(queries_v16::Request::LedgerQuery( queries_v16::LedgerQuery::BlockQuery(5, queries_v16::BlockQuery::GetCurrentPParams), ));