Part 3: Connecting to the Marlin Network

Step 1 - Download and run a Goldfish node

For the purposes of this tutorial, we will use an executable called Goldfish that emulates the Marlin Network locally.

The executable is available here for Linux and here for macOS.

After downloading the executable to the build folder, open a new console and run it using

$ ./goldfish  # You might have given it a different name during download

You might have to change permissions on the file to make it executable using

$ chmod +x ./goldfish  # Add sudo in the beginning if necessary
Verification error on macOS 10.15

You might get a verification error on macOS 10.15 that looks something like this: verify_error To fix this, navigate to System Preferences -> Security & Privacy -> General and click "Allow Anyway" against the goldfish executable: settings_allow

Check that it prints the IP and ports that it is using in the console.

Step 2 - Set up a multicast client

Include the header for the multicast client and the relevant namespaces using

#include <marlin/multicast/DefaultMulticastClient.hpp>

using namespace marlin::multicast;
using namespace marlin::net;

Before we create the client, we need to create a delegate that is notified of important events by the client (e.g. new messages). See the reference documentation for further information on the events that can be listened to.

class MulticastDelegate {
public:
    void did_recv_message(
        DefaultMulticastClient<MulticastDelegate> &client,
        Buffer &&message,
        Buffer &&witness,
        std::string &channel,
        uint64_t message_id
    ) {}

    void did_subscribe(
        DefaultMulticastClient<MulticastDelegate> &client,
        std::string &channel
    ) {
        SPDLOG_INFO("Did subscribe to channel {}", channel);
    }

    void did_unsubscribe(
        DefaultMulticastClient<MulticastDelegate> &client,
        std::string &channel
    ) {
        SPDLOG_INFO("Did unsubscribe from channel {}", channel);
    }
};

Currently, the delegate ignores all messages and prints subscription/unsubscription logs.

Inside the main function, create a keypair that is used by the client for identification.

    uint8_t static_sk1[crypto_box_SECRETKEYBYTES];
    uint8_t static_pk1[crypto_box_PUBLICKEYBYTES];
    crypto_box_keypair(static_pk1, static_sk1);

Inside the main function, initialize a multicast client and delegate. The client can be customized by providing options during initialization. For further information on the available options, please refer to the reference documentation.

    MulticastDelegate del;
    DefaultMulticastClientOptions clop1 {
        static_sk1,  // Secret key
        {"goldfish"},  // Pubsub channels
        "127.0.0.1:9002"  // Beacon address from the goldfish node
    };

    DefaultMulticastClient<MulticastDelegate> cl1(clop1);
    cl1.delegate = &del;

Step 3 - Run the event loop

The Marlin Multicast SDK is fully asynchronous and uses event loops to acheive this.

Run the event loop using

    return DefaultMulticastClient<MulticastDelegate>::run_event_loop();

Once you have followed the above instructions, you should have a main.cpp that looks like this:

#include <marlin/multicast/DefaultMulticastClient.hpp>


using namespace marlin::multicast;
using namespace marlin::net;

class MulticastDelegate {
public:
    void did_recv_message(
        DefaultMulticastClient<MulticastDelegate> &client,
        Buffer &&message,
        Buffer &&witness,
        std::string &channel,
        uint64_t message_id
    ) {}

    void did_subscribe(
        DefaultMulticastClient<MulticastDelegate> &client,
        std::string &channel
    ) {
        SPDLOG_INFO("Did subscribe to channel {}", channel);
    }

    void did_unsubscribe(
        DefaultMulticastClient<MulticastDelegate> &client,
        std::string &channel
    ) {
        SPDLOG_INFO("Did unsubscribe from channel {}", channel);
    }
};

int main() {
    uint8_t static_sk1[crypto_box_SECRETKEYBYTES];
    uint8_t static_pk1[crypto_box_PUBLICKEYBYTES];
    crypto_box_keypair(static_pk1, static_sk1);

    MulticastDelegate del;

    DefaultMulticastClientOptions clop1 {
        static_sk1,
        {"goldfish"},
        "127.0.0.1:9002"
    };

    DefaultMulticastClient<MulticastDelegate> cl1(clop1);
    cl1.delegate = &del;

    return DefaultMulticastClient<MulticastDelegate>::run_event_loop();
}

This sets up a multicast client that connects to the Marlin Network on 127.0.0.1:9002 can send and receive on the goldfish channel. The client automatically talks to the Goldfish node we ran above and sets up PubSub on the given channel. The client calls the corresponding functions in the delegate to notify it of any significant events.

Step 4 - Build and run executable

Build using

$ cmake .. -DCMAKE_BUILD_TYPE=Release
$ make

and run using

$ ./tutorial

Building should have worked and the executable should run. You should see subscription related logs printed here indicating a successful connection between the client and the Marlin Network.

Conclusion

In this part, we learnt how to use the Marlin Multicast SDK to connect to the Marlin Network. In the next part we will learn how to use the Marlin Multicast SDK to send and receive messages using the Marlin Network.