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:
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
.
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:
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:
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:
@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.