Skip to main content

Factory chain (send and receive)

The final chain in our example is the factory chain. The chain should react to production orders emitted from the order chain and should notify when an order is ready for shipment. These would likely be separate steps in a real-world case, but we will simplify this in our example. We can say a product is "manufactured" by increasing its value and reemitting the message directly. The database model is only a single entity. We create a new file factory_chain.rell to hold the logic for this new blockchain:

src/factory_chain.rell
module;

entity manufactured_product {
key id: integer;
mutable quantity: integer;
}

query get_total_manufactured(id: integer) = manufactured_product @? { id }.quantity;

query get_total_manufactured_products() = manufactured_product @* {} ($.to_struct());

Sending and receiving a message

To send and receive messages in a single chain, we will take what we learned from previous sections in our configuration. Let's add a new blockchain in chromia.yml.

chromia.yml
blockchains:
factory-chain:
module: factory_chain
config:
<<: *sender_receiver
icmf:
receiver:
local:
- topic: "L_production"
brid: null

We then handle our message in the extension method again:

src/factory_chain.rell
import lib.icmf.{ send_message };
import lib.icmf.receiver.{ receive_icmf_message };
import messages.{ topic.*, msg };

@extend(receive_icmf_message) function (sender: byte_array, topic: text, body: gtv) {
when (topic) {
PRODUCTION_ORDER -> {
val order = msg.production_details.from_gtv(body);
for (product in order.products) manufacture_product(product);
send_message(SHIPMENT_READY, msg.shipment_ready(order.order_id).to_gtv());
}
else -> require(false, "Message type %s not handled".format(topic));
}
}

function manufacture_product(product: msg.product) {
if (not exists(manufactured_product @? { .id == product.id})) {
create manufactured_product( id = product.id, quantity = product.quantity);
} else {
update manufactured_product @ { .id == product.id } (quantity += product.quantity);
}
}

Testing

Similar to the other blockchain, we configure a new test module:

chromia.yml
blockchains:
factory-chain:
...
test:
modules:
- factory_chain_test

and add a test where we emit a message and make sure the dapp responds by emitting another event:

src/factory_chain_test.rell
@test module;

import factory_chain.*;
import lib.icmf.test.{ test_icmf_message };

function test_manufacture_order() {
rell.test.tx().op(
test_icmf_message(
x"",
PRODUCTION_ORDER,
msg.production_details(
order_id = 1,
products = [msg.product(id = 2, quantity = 10)]
)
.to_gtv()
)
)
.run();
assert_events(("icmf_message", (topic = SHIPMENT_READY, body = msg.shipment_ready(1).to_gtv()).to_gtv_pretty()));
assert_equals(manufactured_product @ { .id == 2 }.quantity, 10);
}

Now, you have successfully written a dapp that uses three separate blockchains. In the final section, we will wrap things up by running the blockchains locally and testing the flow.