Skip to content

Commit

Permalink
new get included message api endpoint (iotaledger#429)
Browse files Browse the repository at this point in the history
* new get included message api endpoint

* Using TransactionId

* Fixed fmt, clippy and tests

* Returning message wrapper

* new mqtt topic added in  spec
  • Loading branch information
melatron authored Mar 18, 2021
1 parent 72a62bc commit 292ef16
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 10 deletions.
10 changes: 10 additions & 0 deletions bindings/nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,16 @@ Get the treasury amount.

**Returns** a promise resolving to the [Treasury](#Treasury).

#### getIncludedMessage(): Promise<Message>

Get the included message of a transaction.

| Param | Type | Description |
| ----- | ------------------- | -------------------------- |
| index | <code>string</code> | The id of the transaction |

**Returns** A promise resolving to the new [Message](#message) instance.

#### reattach(messageId): Promise<Message>

Reattaches the message associated with the given id.
Expand Down
1 change: 1 addition & 0 deletions bindings/nodejs/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export declare class Client {
getReceipts(): Promise<Receipts[]>
getReceiptsMigratedAt(index: number): Promise<Receipts[]>
getTreasury(): Promise<Treasury>
getIncludedMessage(): Promise<MessageWrapper>
reattach(messageId: string): Promise<MessageWrapper>
promote(messageId: string): Promise<MessageWrapper>
}
Expand Down
2 changes: 2 additions & 0 deletions bindings/nodejs/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ Client.prototype.getMilestoneUTXOChanges = promisify(Client.prototype.getMilesto
Client.prototype.getReceipts = promisify(Client.prototype.getReceipts)
Client.prototype.getReceiptsMigratedAt = promisify(Client.prototype.getReceiptsMigratedAt)
Client.prototype.getTreasury = promisify(Client.prototype.getTreasury)
Client.prototype.getIncludedMessage = promisify(Client.prototype.getIncludedMessage)

Client.prototype.retry = promisify(Client.prototype.retry)
const retryUntilIncluded = Client.prototype.retryUntilIncluded
Client.prototype.retryUntilIncluded = function (msg_id, interval, maxAttempts) {
Expand Down
12 changes: 11 additions & 1 deletion bindings/nodejs/native/src/classes/client/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use super::MessageDto;

use crate::classes::client::dto::MessageWrapper;
use iota::{
Address, AddressOutputsOptions, Bech32Address, ClientMiner, MessageBuilder, MessageId, Parents, Seed, UTXOInput,
Address, AddressOutputsOptions, Bech32Address, ClientMiner, MessageBuilder, MessageId, Parents, Seed,
TransactionId, UTXOInput,
};
use neon::prelude::*;

Expand Down Expand Up @@ -68,6 +69,7 @@ pub(crate) enum Api {
GetReceipts(),
GetReceiptsMigratedAt(u32),
GetTreasury(),
GetIncludedMessage(TransactionId),
Retry(MessageId),
RetryUntilIncluded(MessageId, Option<u64>, Option<u64>),
Reattach(MessageId),
Expand Down Expand Up @@ -298,6 +300,14 @@ impl Task for ClientTask {
let treasury = client.get_treasury().await?;
serde_json::to_string(&treasury).unwrap()
}
Api::GetIncludedMessage(transaction_id) => {
let message = client.get_included_message(&*transaction_id).await?;
serde_json::to_string(&MessageWrapper {
message_id: message.id().0,
message,
})
.unwrap()
}
Api::Retry(message_id) => {
let message = client.retry(message_id).await?;
serde_json::to_string(&MessageWrapper {
Expand Down
21 changes: 20 additions & 1 deletion bindings/nodejs/native/src/classes/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

use iota::{
message::prelude::{Address, MessageId, UTXOInput},
message::prelude::{Address, MessageId, TransactionId, UTXOInput},
AddressOutputsOptions, OutputType, Seed,
};
use neon::prelude::*;
Expand Down Expand Up @@ -540,6 +540,25 @@ declare_types! {
Ok(cx.undefined().upcast())
}

method getIncludedMessage(mut cx) {
let transaction_id = cx.argument::<JsString>(0)?.value();
let transaction_id = TransactionId::from_str(transaction_id.as_str()).expect("invalid transaction id");

let cb = cx.argument::<JsFunction>(0)?;
{
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let client_task = ClientTask {
client_id: id.clone(),
api: Api::GetIncludedMessage(transaction_id),
};
client_task.schedule(cb);
}

Ok(cx.undefined().upcast())
}

method reattach(mut cx) {
let message_id = cx.argument::<JsString>(0)?.value();
let message_id = MessageId::from_str(message_id.as_str()).expect("invalid message id");
Expand Down
11 changes: 11 additions & 0 deletions bindings/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,17 @@ Get the treasury amount.

**Returns** the [TreasuryResponse](#TreasuryResponse).

#### get_included_message(): Message

Get the included message of a transaction.

| Param | Type | Description |
| ----- | ------------------- | -------------------------- |
| [index] | <code>string</code> | The id of the transaction |

**Returns** the new [Message](#message).


### High-Level APIs

#### message(seed (optional), account_index (optional), initial_address_index (optional), inputs (optional), input_range_begin (optional), input_range_end (optional), outputs (optional), dust_allowance_outputs (optional), index (optional), index_raw (optional), data (optional), data_str (optional), parents (optional)): Message
Expand Down
6 changes: 5 additions & 1 deletion bindings/python/native/src/client/full_node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::client::{
};
use iota::{
Bech32Address as RustBech32Address, ClientMiner as RustClientMiner, MessageBuilder as RustMessageBuilder,
MessageId as RustMessageId, Parents, UTXOInput as RustUTXOInput,
MessageId as RustMessageId, Parents, TransactionId as RustTransactionId, UTXOInput as RustUTXOInput,
};
use pyo3::prelude::*;

Expand Down Expand Up @@ -128,4 +128,8 @@ impl Client {
fn get_treasury(&self) -> Result<TreasuryResponse> {
Ok(crate::block_on(async { self.client.get_treasury().await })?.into())
}
fn get_included_message(&self, input: String) -> Result<Message> {
let transaction_id = RustTransactionId::from_str(&input[..])?;
crate::block_on(async { self.client.get_included_message(&transaction_id).await })?.try_into()
}
}
4 changes: 2 additions & 2 deletions bindings/python/native/src/client/high_level_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::client::{
};
use iota::{
Bech32Address as RustBech32Address, MessageId as RustMessageId, Seed as RustSeed,
TransactionId as RustTransationId, UTXOInput as RustUTXOInput,
TransactionId as RustTransactionId, UTXOInput as RustUTXOInput,
};
use pyo3::{exceptions, prelude::*};
use std::{
Expand Down Expand Up @@ -52,7 +52,7 @@ impl Client {
if let Some(inputs) = inputs {
for input in inputs {
send_builder = send_builder.with_input(RustUTXOInput::new(
RustTransationId::from_str(&input.transaction_id[..])?,
RustTransactionId::from_str(&input.transaction_id[..])?,
input.index,
)?);
}
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/native/src/client/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use iota::{
Input as RustInput, Message as RustMessage, MilestonePayloadEssence as RustMilestonePayloadEssence,
Output as RustOutput, OutputType, Payload as RustPayload, ReferenceUnlock as RustReferenceUnlock,
RegularEssence as RustRegularEssence, SignatureLockedSingleOutput as RustSignatureLockedSingleOutput,
SignatureUnlock as RustSignatureUnlock, TransactionId as RustTransationId,
SignatureUnlock as RustSignatureUnlock, TransactionId as RustTransactionId,
TransactionPayload as RustTransactionPayload, UTXOInput as RustUTXOInput, UnlockBlock as RustUnlockBlock,
UnlockBlocks as RustUnlockBlocks,
};
Expand Down Expand Up @@ -883,7 +883,7 @@ impl TryFrom<RegularEssence> for RustRegularEssence {
.iter()
.map(|input| {
RustUTXOInput::new(
RustTransationId::from_str(&input.transaction_id[..]).unwrap_or_else(|_| {
RustTransactionId::from_str(&input.transaction_id[..]).unwrap_or_else(|_| {
panic!(
"invalid UTXOInput transaction_id: {} with input index {}",
input.transaction_id, input.index
Expand Down
23 changes: 22 additions & 1 deletion iota-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use crate::{
node::*,
};
use bee_common::packable::Packable;
use bee_message::prelude::{Address, Bech32Address, Message, MessageBuilder, MessageId, Parents, UTXOInput};
use bee_message::prelude::{
Address, Bech32Address, Message, MessageBuilder, MessageId, Parents, TransactionId, UTXOInput,
};
use bee_pow::providers::{MinerBuilder, Provider as PowProvider, ProviderBuilder as PowProviderBuilder};
use bee_rest_api::types::{
dtos::{MessageDto, PeerDto, ReceiptDto},
Expand Down Expand Up @@ -924,6 +926,25 @@ impl Client {
Ok(resp.data)
}

/// GET /api/v1/transactions/{transactionId}/included-message
/// Returns the included message of the transaction.
pub async fn get_included_message(&self, transaction_id: &TransactionId) -> Result<Message> {
let mut url = self.get_node().await?;
let path = &format!("api/v1/transactions/{}/included-message", transaction_id);
url.set_path(path);
#[derive(Debug, Serialize, Deserialize)]
struct ResponseWrapper {
data: Message,
}
let resp: ResponseWrapper = self
.http_client
.get(url.as_str(), GET_API_TIMEOUT)
.await?
.json()
.await?;

Ok(resp.data)
}
/// Reattaches messages for provided message id. Messages can be reattached only if they are valid and haven't been
/// confirmed for a while.
pub async fn reattach(&self, message_id: &MessageId) -> Result<(MessageId, Message)> {
Expand Down
8 changes: 6 additions & 2 deletions iota-client/src/node/mqtt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ impl Topic {
Regex::new("addresses/(iota|atoi|iot|toi)1[A-Za-z0-9]+/outputs").expect("regex failed"),
// ED25519 address hex
Regex::new("addresses/ed25519/([A-Fa-f0-9]{64})/outputs").expect("regex failed"),
Regex::new(r"messages/indexation/([a-f0-9]{2,128})").expect("regex failed")
Regex::new(r"messages/indexation/([a-f0-9]{2,128})").expect("regex failed"),
Regex::new(r"transactions/([A-Fa-f0-9]{64})/included-message").expect("regex failed"),
].to_vec() => Vec<Regex>
);

Expand Down Expand Up @@ -137,7 +138,10 @@ fn poll_mqtt(mqtt_topic_handlers_guard: Arc<RwLock<TopicHandlerMap>>, mut event_
let mqtt_topic_handlers = mqtt_topic_handlers_guard.read().await;
if let Some(handlers) = mqtt_topic_handlers.get(&Topic(topic.clone())) {
let event = {
if topic.as_str() == "messages" || topic.contains("messages/indexation/") {
if topic.as_str() == "messages"
|| topic.contains("messages/indexation/")
|| topic.contains("transactions/")
{
let mut payload = &*p.payload;
match Message::unpack(&mut payload) {
Ok(iota_message) => match serde_json::to_string(&iota_message) {
Expand Down
18 changes: 18 additions & 0 deletions iota-client/tests/node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,21 @@ async fn test_get_treasury() {

println!("{:#?}", r);
}

#[tokio::test]
#[ignore]
async fn test_get_included_message() {
let r = iota_client::Client::builder()
.with_node(DEFAULT_NODE_URL)
.unwrap()
.finish()
.await
.unwrap()
.get_included_message(
&TransactionId::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap(),
)
.await
.unwrap();

println!("{:#?}", r);
}
24 changes: 24 additions & 0 deletions specs/iota-rs-ENGINEERING-SPEC-0000.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* [`get_receipts`](#get_receipts)
* [`get_receipts_migrated_at`](#get_receipts_migrated_at)
* [`get_treasury`](#get_treasury)
* [`get_included_message`](#get_included_message)
* [Objects](#Objects)
* [Network]
* [Seed]
Expand Down Expand Up @@ -614,6 +615,28 @@ pub struct TreasuryResponse {
}
```

## `get_included_message()`

(`GET /transactions/{transactionId}/included-message`)

Get the included message of the transaction.

### Parameters

| Parameter | Required | Type | Definition |
| - | - | - | - |
| **transaction_id** || [TransactionId] | The id of the transaction. |

### Returns

```Rust
struct Message {
parents: Vec<MessageId>,
payload: Option<Payload>,
nonce: u64,
}
```

# Objects

Here are the objects used in the API above. They aim to provide a secure way to handle certain data structures specified in the Iota stack.
Expand Down Expand Up @@ -864,6 +887,7 @@ messages
messages/referenced
messages/indexation/{index}
messages/{messageId}/metadata
transactions/{transactionId}/included-message
outputs/{outputId}
Expand Down

0 comments on commit 292ef16

Please sign in to comment.