SIP: 3
Title: Remote Notifications and Triggers
Author: Lily Anne Hall
Status: Active
Type: Standard
Created: 2016-08-10

Abstract

Protocol extension that gives nodes the capability to opt-in to passive generic notifications from other nodes and services as well as authorize certain types of notifications and senders to trigger behavior within client applications implementing this SIP.

Motivation

Applications implementing the Storj protocol are designed for a variety of use-cases and the resulting relationships between applications on the network can become far more nuanced than a simple 1-1 transaction. To illustrate this we cite the introduction of Storj Bridge as a broker between a “thin client” renter and a farmer.

The introduction of a broker brings with it the need for arbitration measures in the event that one of the parties acts outside of the terms of the storage contract. Given that it is difficult to predict how future systems will implement these measures, we propose a generic notification format to allow nodes to invent meta-protocols that may trigger application specific behaviors.

Example: Farmer Information Requests

Organizations (like Storj Labs) may be responsible for collecting information from farmers due to regulatory compliance and tax purposes when issuing payouts above a certain amount. To notify a farmer when that information needs to be provided, the Storj Share client application could opt-in to receive triggers from Storj Labs to show a prompt when the owed amount exceeds a threshold.

Example: Third Party Transfer Verification

Contract brokers, like the operator of a Storj Bridge, need to know when a data transfer between two parties succeeds or fails so that it can appropriately track the performance and reliability of the farmers it selects in the future. The method for implementing these proofs and verifications is outside the scope of this SIP, however it is likely that there will be a number of future strategies for carrying out this work. To avoid the need for a new strategy to become accepted into the core protocol, nodes that support the given strategy can use these custom triggers to request and deliver the information needed to carry them out.

Specification

This SIP proposes the addition of a new protocol extension to add a TRIGGER RPC message for the purpose of sending a custom payload to a consenting node on the network. The intent is to allow nodes to establish a relationship with each other that grants one or both parties license to “trigger” some behavior in the software running on the other party’s host.

Message Format

This specification does not rigidly define any application behaviors - it’s only purpose is to define the message structure and rules surrounding how an application-specific trigger should be issued and handled. Like the rest of the Storj Protocol, this message is formatted according to the JSON-RPC 2.0 definition and includes all of the standard required Storj protocol parameters.

In addition to the required parameters, the TRIGGER method requires:

Below is a possible example of a trigger that might be sent from a farmer to a third party bridge node to prove that she successfully received all of the data from a renter whose storage contract was brokered by the bridge:

{
  "method": "TRIGGER",
  "params": {
    "behavior": "ProveUploadReceipt",
    "contents": {
      "rmd160sha265": "cebaa98c19807134434d107b0d3e5692a516ea66",
      "sha1whirlpool": "43144cac0a406eb72f4d3be7292438ac15725e1d"
    },
    "contact": {
      "address": "10.0.0.2",
      "port": 1337,
      "nodeID": "89cc3ddb4209c6e7e301c10c0257adf4fd85f253",
      "protocol": "0.7.2"
    },
    "nonce": 1455216323786,
    "signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b68281a9882..."
  },
  "id": "7b6a2ab35da6826995abf3310a4875097df88cdb"
}

In the example above the renter has provided the bridge with two different hashes of the data it wishes to upload. The bridge publishes a contract to the network that is keyed on the RMD-160(SHA256(data)), so that hash is known. Once the bridge negotiates a contract with a farmer and brokers the data channel, the farmer must prove to the bridge that she received all of the data from the renter by calculating the second secret hash from the transferred data.

Once the secret hash is calculated, the farmer sends a TRIGGER to the bridge (who has authorized the trigger previously and is expecting it) that includes both hashes. This would trigger a behavior in the bridge to update it’s record that the farmer did receive the data.

Note that the ProveUploadReceipt behavior is not part of the Storj protocol, but is an application-specific trigger that must be implemented by the both the client software and the target node.

Likewise, the response to a trigger message follows the Storj protocol and can include any arbitrary response values:

{
  "result": {
    "message": "Upload proof successfully recorded",
    "contact": {
      "address": "api.storj.io",
      "port": 4001,
      "nodeID": "98dc026fa01ae26822bfb23f98e725444d6775b0",
      "protocol": "0.7.2"
    },
    "nonce": 1455216323786,
    "signature": "904502207e8a439f2cb33055e0b2e2d90e775f29d90b3ad85aec0c..."
  },
  "id": "7b6a2ab35da6826995abf3310a4875097df88cdb"
}

To further clarify the point, the TRIGGER message format and the advisements for handling should become an extension to the Storj protocol, but the types of behaviors and their associated content may remain application-specific, or alternatively, be proposed as their own SIP if desired. The trigger RPC acts as a sort of envelope for any number of sub-protocols that tenants of the Storj network may implement and adopt without the need to reach community consensus as the handling of triggers is up to each individual application.

Authorization Practices

Clients choosing to implement support for triggers should take care to provide a safe interface for enabling triggers. To ensure that application behavior can only be triggered by parties that have been explicitly authorized to do so, the minimum best practices to follow are:

Example Code

Assuming the use of Storj Core, authorizing a trigger might resemble the following:

var storj = require('storj');
var network = new storj.RenterInterface(options);

// When a contract is negotiated and data channel is authorized...
network.triggers.add(farmerNodeId, {
  ProveUploadReceipt: function(msgParams, replyToSender, destroyTrigger) {
    var secretHashExpected = somehowGetSecretHash();
    var secretHashReceived = msgParams.contents.sha1whirlpool;

    // If the provided hash doesn't match, then respond with error and destroy
    // this trigger handler (to be added again when needed)
    if (secretHashReceived !== secretHashExpected) {
      replyToSender(new Error('Invalid secret hash provided'));
      return destroyTrigger();
    }

    // Update our record of the farmer's receipt of the data and respond with
    // an acknowledgement
    somehowUpdateThisFarmersRecord();
    replyToSender(null, { message: 'Upload proof successfully recorded' });
    destroyTrigger();
  }
});

This example demonstrates a safe interface for accepting triggers for a couple of reasons:

  1. The implementor must explicitly define a trigger handler for the Node ID
  2. The implementor must explicitly define the expected behavior to handle
  3. The implementor is provided an interface to easily unregister the trigger

Other Use Cases