Chromia
Start Building

06 / 07Advanced

The factory chain: sending and receiving

The factory chain is the last chain in the example. It listens for production orders that the order chain emits and announces when an order is ready to ship. A real system would probably split these into separate steps, but the example keeps them together for simplicity.

Here, "manufacturing" a product means increasing its value and emitting the message again right away. The database model has just one entity. Put the logic for this blockchain in a new module, factory_chain, inside the src/factory_chain directory, with this content:

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

In src/factory_chain/entities.rell, define the matching entity for manufactured products:

src/factory_chain/entities.rell
entity manufactured_product {    key id: integer;    mutable quantity: integer;}

Next, add two queries to src/factory_chain/queries.rell. One returns the quantity of a manufactured product, and the other returns the total count of manufactured products.

src/factory_chain/queries.rell
query get_total_manufactured(id: integer) = manufactured_product @? { id }.quantity;query get_total_manufactured_products() = manufactured_product @* {} ( $.to_struct() );

Sending and receiving a message

Configuring a chain to both send and receive messages builds on the configuration from earlier sections. In chromia.yml, add a factory_chain property with its configuration under the blockchains section. This defines the new blockchain.

chromia.yml
blockchains:  # ↓↓↓ Add this code snippet ↓↓↓  factory_chain:    module: factory_chain    config:      <<: *sender_receiver      icmf:        receiver:          local:            - topic: "L_production"              brid: null  # ↑↑↑ Add this code snippet ↑↑↑

To handle the messages, add this code to functions.rell:

src/factory_chain/functions.rell
@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 -> log("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

Testing the factory chain requires extra configuration in chromia.yml. Under the factory_chain section, add a test property and the related details.

chromia.yml
blockchains:  factory-chain:    # ↓↓↓ Add this code snippet ↓↓↓    test:      modules:        - test.factory_chain_test    # ↑↑↑ Add this code snippet ↑↑↑

The test emits a message, and the dapp reacts by emitting an event. In the src/test directory, create factory_chain_test.rell with the following code:

src/test/factory_chain_test.rell
@test module;import factory_chain.{ manufactured_product };import messages.{ msg, topic.* };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);}

Run chr test and check the results.

bash
Running tests for chain: factory-chainTEST: factory_chain_test:test_manufacture_orderOK: factory_chain_test:test_manufacture_order (0.688s)------------------------------------------------------------TEST RESULTS:OK factory_chain_test:test_manufacture_orderSUMMARY: 0 FAILED / 1 PASSED / 1 TOTAL (0.688s)***** OK *****

You now have a dapp built on three separate blockchains. The final section covers running the blockchains locally and testing the complete flow.

For reference, the project structure and the full chromia.yml configuration after these changes are shown below. Use them to compare against your own project at this point in the course:

Project structure

text
order-system-example/ ├── build/ ├── src/ │   ├── delivery_chain/ │   │   ├── entities.rell │   │   ├── functions.rell │   │   ├── module.rell │   │   ├── operations.rell │   │   └── queries.rell │   ├── factory_chain/ │   │   ├── entities.rell │   │   ├── functions.rell │   │   ├── module.rell │   │   └── queries.rell │   ├── lib/ │   ├── order_chain/ │   │   ├── entities.rell │   │   ├── functions.rell │   │   ├── module.rell │   │   ├── operations.rell │   │   └── queries.rell │   ├── test/ │   │   ├── delivery_chain_test.rell │   │   ├── factory_chain_test.rell │   │   └── order_chain_test.rell │   └── messages.rell ├── .gitignore └── chromia.yml 

Final version of the chromia.yml file

chromia.yml
definitions:  - &sender # Configuration for a chain that sends messages    gtx:      modules:        - "net.postchain.d1.icmf.IcmfSenderGTXModule"  - &receiver # Base configuration for a chain that receives messages    gtx:      modules:        - "net.postchain.d1.icmf.IcmfReceiverGTXModule"    sync_ext:      - "net.postchain.d1.icmf.IcmfReceiverSynchronizationInfrastructureExtension"  - &sender_receiver # Base configuration for a chain that will both send and receive messages    gtx:      modules:        - "net.postchain.d1.icmf.IcmfSenderGTXModule"        - "net.postchain.d1.icmf.IcmfReceiverGTXModule"    sync_ext:      - "net.postchain.d1.icmf.IcmfReceiverSynchronizationInfrastructureExtension"blockchains:  order_chain:    module: order_chain    config:      <<: *sender    test:      modules:        - test.order_chain_test  delivery_chain:    module: delivery_chain    config:      <<: *receiver      icmf:        receiver:          local:            - topic: "L_delivery"              brid: null            - topic: "L_shipment_ready"              brid: null    test:      modules:        - test.delivery_chain_test  factory-chain:    module: factory_chain    config:      <<: *sender_receiver      icmf:        receiver:          local:            - topic: "L_production"              brid: null    test:      modules:        - test.factory_chain_testcompile:  rellVersion: 0.14.9database:  schema: schema_order_system_examplelibs:  icmf:    registry: https://gitlab.com/chromaway/core/directory-chain    path: src/lib/icmf    tagOrBranch: 1.90.1    rid: x"B56524EE85B679371EAB1A069B03BE6A3E94F36993DEA900747BA5BAE8B99122"

Written for this site from Chromia’s public course. Code samples are the course’s own.