InstallingTheServer
This first version of the server is standalone -- it does not implement the Ripple protocol for inter-server transactions. That comes later. First we'll get the client protocol nailed.
Get the code from:
http://github.com/rfugger/ripple/
Install (by linux package system preferably):
- python 2.5 or higher,
- twisted 2.5,
- the latest sqlalchemy (the svn trunk version is best*)
- sqlite and pysqlite (for testing) or another sqlalchemy supported DB, like postgresql (for production or testing multiple simultaneous connections).
(* keep a fresh checkout of the sqlalchemy svn repository trunk (http://svn.sqlalchemy.org/sqlalchemy/trunk) somewhere, and link to the lib/sqlalchemy directory in /usr/local/lib/python2.5/site-packages, or wherever your python install's site-packages directory is located.)
Make sure your PYTHONPATH environment variable includes the directory where you put the ripplebase code (ie, the directory containing the ripplebase directory).
Settings for various things like the database are in ripplebase/settings.py.
Then in the ripplebase directory, run python createdb.py
to (re)create the database, and python server.py
to start the server. The default port is 8080.
To run the test suite: trial test
.
What the server can do so far
Communication with the server uses HTTP, with data in JSON format, utf-8 encoded, of course.
Units
Ripple clients need a common set of value units to refer to when creating accounts and making payments. Any client may add a value unit by name, and all clients may refer to all such units.
- POST a new unit to
/units/
:
{"name": <unitname>}
- GET a list of units at
/units/
.
Addresses
Ripple addresses are identities for sending and receiving payments, like email addresses are identities for sending and receiving email. An address can have zero or more accounts (described below), although it is not useful for payment until it has at least one account.
- POST a new address to
/addresses/
:
{"address": <address>, "owner": <string>, "accounts": [<accountname1>, <accountname2>, ...]}
The owner
field simply stores an arbitrary string for the client, and may be used to identify the user on the client system that this address belongs to. accounts
is optional. Accounts must exist before being added to an address. See below.
- GET a list of addresses at
/addresses/
- GET an individual address at
/addresses/<address>/
- POST a change to an address at
/addresses/<address>/
Only the fields with new values need to be included.
Accounts
A credit relationship connection between two participants in the system is made of two accounts, one for each participant. (You could say each participant keeps its own copy of the account.)
- POST a new account to
/accounts/
:
{"name": <accountname>, "owner": <string>, "balance": <decimal_string>, "unit": <unitname>, "upper_limit": <decimal_string>, "lower_limit": <decimal_string>, "limits_expiry_time": <YYYY-MM-DD HH:mm:ss>, "address": <address>, "partner": <address>, "note": <string>}
The owner
field, like in addresses, is for the arbitrary use of the client. decimal_string
means that decimal numbers are passed as JSON strings to avoid them getting parsed into floats, which can mean loss of precision or accuracy. limits_expiry_time
is how long the specified limits are good for. It can be null
, meaning they never expire. address
is the address this account should appear to be from when it is presented to the other participant. partner
is an address for the other party to the account, so Ripple knows who should get the request to register an account.
Posting a new account generates an account confirmation request for the account partner. The partner must confirm by posting her own version of the account before the account is made active.
- GET a list of accounts at
/accounts/
, in the format:
{"name": <accountname>, "relationship": <integer>, "owner": <string>, "balance": <decimal_string>, "unit": <unitname>, "upper_limit": <decimal_string>, "lower_limit": <decimal_string>, "limits_effective_time": <YYYY-MM-DD HH:mm:ss>, "limits_expiry_time": <YYYY-MM-DD HH:mm:ss>, "is_active": <boolean>}
relationship
is the internal Ripple ID that links this account with its dual version owned by the account partner. limits_effective_time
is the time these limits came into effect. is_active
is whether the account is able to be used for transactions at this time.
- GET an individual account at
/accounts/<accountname>/
- POST a change to an account at
/accounts/<accountname/
.limits_effective_time
andrelationship
are set internally by the server and are read-only. - GET a list of account confirmation requests at
/accountrequests/
, in the format:
{"relationship": <integer>, "source_address": <address>, "dest_address": <address>, "unit": <unitname>, "note": <note>}
- POST an account confirmation to
/accounts/
:
{"name": <accountname>, "relationship": <integer>, "owner": <string>, "balance": <decimal_string>, "unit": <unitname>, "upper_limit": <decimal_string>, "lower_limit": <decimal_string>, "limits_expiry_time": <YYYY-MM-DD HH:mm:ss>}
name
and owner
do not need to be, and generally will not be, the same as the initiating partner's original account -- account names IDs for client use, and this new account may be on a different client than the original account. Similarly, unit
need not be the same as the original account, although please note that in this case Ripple assumes that these are different notations for the same unit and never performs any value conversions between the two accounts that comprise a credit relationship. Both accounts should become active once the second one is posted as confirmation.
Exchange Rates
Each client can define as many named exchange rates as it wants. Exchange rates determine the rate at which that client will exchange value on one account or payment unit for value on another account or payment unit (see Exchanges below).
- POST a new exchange rate to
/rates/
:
{"name": <ratename>, "value": <decimal_string>, "expiry_time": <YYYY-MM-DD HH:mm:ss>}
The expiry time is when the given value for this rate expires if it is not updated. That means that any transactions that depend on this rate being known will not be processed.
- GET a list of exchange rates at
/rates/
.
When retrieving exchange rates, there is an addition read-only field effective_time
.
- POST a change to a rate to
/rates/<ratename/
.
Exchanges
Exchanges tell the Ripple server how different accounts can be connected together for building payment paths. There are three types of exchanges: thru-exchanges, in-exchanges, and out-exchanges.
Thru-exchanges define an exchange rate from one account to another account. A payment path can be viewed as a sequence of thru exchanges, beginning on the paying account, and ending on the receiving account.
In-exchanges define an exchange rate between an account for receiving payment and a payment unit. In-exchanges allow Ripple to convert a payment amount to an amount on the receiving account, for when a payment specifies that the recipient receive a pre-defined amount. In-exchanges determine which payment units may be used to receive payment on a particular account.
Out-exchanges define an exchange rate between a payment unit and an account for sending payment. Out-exchanges allow Ripple to convert a payment amount to an amount on the paying account, for when a payment specifies that the payer pay a specified amount. Out-exchanges determine which payment units may be used to send payment from a particular account.
- POST a new thru-exchange to
/exchanges/
:
{"from": <sourceaccountname>, "to": <targetaccountname>, "rate": <ratename>}
This tells the server that it may, as part of Ripple transactions, convert value on the from
account to value on the to
account at the rate given. (The amount on the source account is multiplied by the rate value to determine the amount on the target account.)
- GET a list of thru-exchanges at
/exchanges/
. - POST a change to a thru-exchange at
/exchanges/<sourceaccountname>/<targetaccountname>/
.
The only field the client is permitted to change is rate
, by specifying the name of a different exchange rate.
- POST a new in-exchange to
/inexchanges/
:
{"from": <receivingaccountname>, "to": <unitname>, "rate": <ratename>}
This tells the server that it may receive payment in the specified value unit to the specified account at the specified rate. The conversion takes place by multiplying the amount in account units by the rate to get the amount in payment units.
- GET a list of in-exchanges at
/inexchanges/
. - POST a change to an in-exchange at
/inexchanges/<receivingaccountname>/<unitname>/
.
The only field the client is permitted to change is rate
, by specifying the name of a different exchange rate.
If the key order, <receivingaccountname>
followed by <unitname>
, seems confusing, just remember that all exchanges are addressed by the from
field, followed by the to
field.
- POST a new out-exchange to
/outexchanges/
:
{"from": <unitname>, "to": <payingaccountname>, "rate": <ratename>}
This tells the server that it may send payment in the specified value unit from the specified account at the specified rate. The conversion takes place by multiplying the amount in payment units by the rate to get the amount in account units.
- GET a list of out-exchanges at
/outexchanges/
. - POST a change to an out-exchange at
/outexchanges/<unitname/<payingaccountname>/
.
The only field the client is permitted to change is rate
, by specifying the name of a different exchange rate.
Next up, payments. To get an idea of where this is going, look at ClientAPI.