-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6608ce1
commit 3ae16d9
Showing
3 changed files
with
446 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
``` | ||
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](https://github.com/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](http://storj.github.io/core/tutorial-protocol-spec.html), 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: | ||
|
||
* **behavior**: *String* - Arbitrary identifier for the behavior to trigger | ||
* **contents**: *Object* - Dictionary of named parameters and their values | ||
|
||
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: | ||
|
||
```json | ||
{ | ||
"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: | ||
|
||
```json | ||
{ | ||
"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: | ||
|
||
* Triggers are only enabled on a *whitelist* and *opt-in* basis | ||
* Whitelist is based on `nodeID` *and* `behavior` | ||
* Add a trigger to the whitelist only when you are expecting it | ||
* Remove the trigger from the whitelist when you are longer expecting it | ||
* Process all messages, *especially triggers*, after signature verification | ||
|
||
#### Example Code | ||
|
||
Assuming the use of [Storj Core](http://storj.github.io/core), authorizing a | ||
trigger might resemble the following: | ||
|
||
```js | ||
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 | ||
--------------- | ||
|
||
* IoT integration with a Storj farm (power management, failure recovery, etc) | ||
* Automatic notification of renter/bridge when a farmer is shutting down | ||
* Web of trust based blacklisting or "tattling" on bad actors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
``` | ||
SIP: 4 | ||
Title: Contract Transfers and Renewals | ||
Author: Lily Anne Hall | ||
Braydon Fuller | ||
Status: Active | ||
Type: Standard | ||
Created: 2016-10-26 | ||
``` | ||
|
||
Abstract | ||
-------- | ||
|
||
The SIP introduces a new RPC method to the Storj protocol to enable renting | ||
actors on the network to instruct the custodians of their data to modify | ||
certain contract terms for a given shard. | ||
|
||
Motivation | ||
---------- | ||
|
||
This addition solves two immediate problems: | ||
|
||
1. Efficiently renewing existing contracts without the neccessity of publishing | ||
entirely new ones to extend the length of storage time. | ||
2. Providing an upgrade path for [HD Identity](sip-0032.md) transfer from a | ||
standard Node ID. | ||
|
||
Specification | ||
------------- | ||
|
||
We propose a new RPC method, `RENEW`, which may be issued to a farming node at | ||
any time to modify the terms of a contract for which the issuing party is | ||
authorized. In addition to the standard required parameters, the `RENEW` RPC | ||
includes 3 more: | ||
|
||
* **contract** - the new modified/updated contract data | ||
* **renter_id** - the Node ID authorized for the original contract | ||
* **renter_signature** - the new contract signature by the original Node ID | ||
|
||
### Message Format | ||
|
||
When a renting node wishes to modify the terms of a given storage contract, | ||
it issues a `RENEW` RPC message to the farmer including the required | ||
parameters. Not all contract parameters may be modified in a contract renewal, | ||
the allowed modifications are limited to: | ||
|
||
* **renter_id** | ||
* **renter_hd_key** | ||
* **renter_hd_index** | ||
* **renter_signature** | ||
* **store_begin** | ||
* **store_end** | ||
|
||
Recipient farmers must take care to validate the modifications to prevent loss | ||
of future payments. In the example below, a renting node is instructing the | ||
farming node to transfer the authorization/ownership to a new SIP32 based | ||
identity as well as extending the contract period by an additional 90 days. | ||
|
||
```json | ||
{ | ||
"method": "RENEW", | ||
"params": { | ||
"renter_id": "43144cac0a406eb72f4d3be7292438ac15725e1d", | ||
"renter_signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b68281a...", | ||
"contract": { | ||
"version": 0, | ||
"renter_id": "608939ffcaac7d8019ab43bd097124025d3c47e9", | ||
"renter_hd_key": "xpub6AMzSjSPt3Dc3Z1nziingqQcbHFLtKMsVjYXW1HSPDFihcj...", | ||
"renter_hd_index": 0, | ||
"renter_signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b6828...", | ||
"farmer_id": "8d225ed9aec6e2dfb74d51c84c58ff13d11cfa79", | ||
"farmer_signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b6828...", | ||
"data_size": 8388608, | ||
"data_hash": "e6114b9763d433808f6fdf632c00b919a439bc97", | ||
"store_begin": 1477505878758, | ||
"store_end": 1485281902724, | ||
"audit_count": 3, | ||
"payment_storage_price": 0, | ||
"payment_download_price": 0, | ||
"payment_destination": "1DL5N2ayoUxHwgD2NEZ4ifq1wVRVLVQyk2" | ||
}, | ||
"contact": { | ||
"address": "10.0.0.2", | ||
"port": 1337, | ||
"nodeID": "89cc3ddb4209c6e7e301c10c0257adf4fd85f253", | ||
"protocol": "0.7.2" | ||
}, | ||
"nonce": 1455216323786, | ||
"signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b68281a9882..." | ||
}, | ||
"id": "7b6a2ab35da6826995abf3310a4875097df88cdb" | ||
} | ||
``` | ||
|
||
Upon receipt of a `RENEW` RPC, the farmer must inspect the contract and | ||
perform a local lookup of any contracts associated with the given `data_hash`. | ||
If a contract is found for the shard and the original `renter_id`, then the | ||
farmer must verify the signature from the original identity and validate the | ||
contract modifications - including signature verification for the new identity. | ||
|
||
If these checks pass, the farmer must sign the new contract and respond to the | ||
request with it's updated copy after updating it's own local record. | ||
|
||
```json | ||
{ | ||
"result": { | ||
"contract": { | ||
"version": 0, | ||
"renter_id": "608939ffcaac7d8019ab43bd097124025d3c47e9", | ||
"renter_hd_key": "xpub6AMzSjSPt3Dc3Z1nziingqQcbHFLtKMsVjYXW1HSPDFihcj...", | ||
"renter_hd_index": 0, | ||
"renter_signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b6828...", | ||
"farmer_id": "8d225ed9aec6e2dfb74d51c84c58ff13d11cfa79", | ||
"farmer_signature": "3045022100de2e162d017a1e9d0ebfe2a94df3fc847b6828...", | ||
"data_size": 8388608, | ||
"data_hash": "e6114b9763d433808f6fdf632c00b919a439bc97", | ||
"store_begin": 1477505878758, | ||
"store_end": 1485281902724, | ||
"audit_count": 3, | ||
"payment_storage_price": 0, | ||
"payment_download_price": 0, | ||
"payment_destination": "1DL5N2ayoUxHwgD2NEZ4ifq1wVRVLVQyk2" | ||
}, | ||
"contact": { | ||
"address": "api.storj.io", | ||
"port": 4001, | ||
"nodeID": "98dc026fa01ae26822bfb23f98e725444d6775b0", | ||
"protocol": "0.7.2" | ||
}, | ||
"nonce": 1455216323786, | ||
"signature": "904502207e8a439f2cb33055e0b2e2d90e775f29d90b3ad85aec0c..." | ||
}, | ||
"id": "7b6a2ab35da6826995abf3310a4875097df88cdb" | ||
} | ||
``` | ||
|
||
Upon receipt of the response, the renting node, must update it's local record | ||
of the storage contract once more, to include the updated signature from the | ||
farming node. Once this exchange is completed, the contract has been | ||
successfully transferred and/or renewed. | ||
|
||
|
Oops, something went wrong.