_images/laptop.png

RPC Interface

The RPC interface to Uplink is an HTTP based API for which all HTTP requests methods are type POST, directed at (default) port 8545 on a server which hosts a Uplink node. There are two types of requests in this interface– the Query and the Command. Queries are not stateful and do not cause any side effects on the server other than looking up data on the ledger. Commands, however, are stateful and their purpose is to create or modify values on the ledger, sending commands directly into the P2P network; Commands issue transactions on the ledger.

The RPC protocol is configured by the rpc section in the node configuration. The port, headers and SSL configuration can be set manually:

rpc
{
  port         = 8545
  ssl          = false
  key          = "key.pem"
  crt          = "certificate.pem"
  cors-origin  = []
  cors-headers = []
}

Endpoints

Status

  • /health
  • /version
  • /peers

Blocks

  • /blocks
  • /blocks/:blockId

Accounts

  • /accounts
  • /accounts/:address

Assets

  • /assets
  • /assets/:address

Contracts

  • /contracts
  • /contracts/:address

Transactions

  • /transactions/:blockId
  • /transactions/:blockId/:transactionId

MemPool

  • /transactions/pool/size
  • /transactions/pool/all
  • /transactions/pool/all/sizes

Commands

Currently, the only Commands that can be issued to the RPC interface, targeting the / endpoint, must have a JSON body that represents a well-formed Transaction.

All Commands

Well formed Transactions (where the TransactionHeader must also be well formed) have the form:

{
  "header" : TransactionHeader,
  "signature" : String (Base64 Sha256 hash)
  "from" : String (Address),
  "fromPub" : String (ECDSA Public key fingerprint),
  "timestamp" : Timestamp (Unix Timestamp, Int64)
}

TODO: enumerate JSON of all transaction headers

Success Responses
All RPC requests, if successful, will respond with a JSON body of the form:
{
  "tag" : "RPCResp",
  "contents" : ...
}

when the requests have data to return, or simply:

{
  "tag" : "RPCRespOK"
  "contents" : null
}

when the requests have no data to return.

Error Responses
All RPC queries can fail with an error response. All error responses will be returned as a JSON objects unless otherwise specified and have the form:
Code: 200 - OK

Body:
{
  "tag" : "RPCRespError,
  "contents" :
    {
      "errorType" : String,
      "errorMsg" : String
    }
}

Queries

Queries request data from the RPC

Health

Check the whether the server is alive.

URL: /health

Success Response:

Code: 200 - OK

Body: {}

Error Response:

Code: 500

Body: {}

Version

Status

Returns the server’s version of Uplink, git branch name, git commit hash, and whether or not there are unstaged commits in the deployed repo.

URL: /version

Success Response:

Code: 200 - OK

Body:
{
  "version" : String
  "branch"  : String
  "commit"  : String
  "dirty"   : String
}

Error Response

Code: 500

Body: {}

Blocks

All Blocks

Get all blocks on the chain

URL: /blocks

Success Response:

Code: 200 - OK

Body:
  [ {
      "header" :
        {
          "origin" : String (sha256),
          "prevBlock" : String (sha256),
          "merkleRoot" : String (sha256),
          "timestamp" : Int (Unix Timestamp)
        }
      "signature" : String,
      "index" : Int,
      "transactions" : [Transaction]
    },
    ...
  ]

Block by Index

Get a specific block on the chain by specifying a block index

URL: block/:blockIdx

Success Response:

Code: 200 - OK

Body:
{
  "header" :
    {
      "origin" : String,
      "prevBlock" : String,
      "merkleRoot" : String,
      "timestamp" : Int
    }
  "signature" : String,
  "index" : Int,
  "transactions" : [Transaction]
}

Peers

All Peers

Get a list of all peers (hostname:port) in the network

URL: /peers

Success Response:

Code: 200 - OK

Body: [ String, String, ... ]

Accounts

All Accounts

Get all accounts in the network

URL: /accounts

Success Response:

Code: 200 - OK

Body:
[ {
    "publicKey" : String,
    "address" : String,
    "nodeKey" : Int,
    "timezone" : String,
    "metadata" :
      {
        String : String,
        String : String,
        ...
      }
  },
  ...
]

Account by Address

Get a specific account by providing an address

URL: /accounts/:address

Success Response:

Code: 200 - OK

Body:
{
  "publicKey" : String,
  "address" : String (sha256),
  "nodeKey" : Int,
  "timezone" : String,
  "metadata" :
    {
      String : String,
      String : String,
      ...
    }
}

Assets

All Assets

Get all assets in the network

URL: /assets

Success Response:

Code: 200 - OK

Body:
[
  {
    "asset": {
      "issuedOn": Int (Unix Timestamp),,
      "assetType": {
        "type": String,
        "precision": Int
      },
      "name": String,
      "reference":  String || null,
      "supply": Int,
      "holdings": {
        String (Address) : Int,
        String (Address) : Int,
        ...
      },
      "issuer":  String (Address),
    },
    "address": String (Address)
  },
  ...
]

Asset by Address

Get a specific asset in the network by providing the address of the asset

URL: /assets/:address

Success Response:

Code: 200 - OK

Body:
{
  "asset": {
    "issuedOn": Int (Unix Timestamp),
    "assetType": {
      "type": String,
      "precision": Int
    },
    "name": String,
    "reference":  String || null,
    "supply": Int,
    "holdings": {
      String (Address) : Int,
      String (Address) : Int,
      ...
    },
    "issuer":  String (Address),
  },
  "address": String (Address)
}

Contracts

All Contracts

Get all contracts on the ledger

URL: /contracts

Success Response:

Code: 200 - OK

Body:
[
  {
    "contract": {
      "timestamp": Int,
      "storage": {
        String : String
        String : String
        ...
      },
      "methods": [string,...],
      "script": String (code)
    },
    "address": String (Address)
  }
  ...
]

Contract by Address

Get a specific contract by providing the address of the contract

URL: /contracts/:address

Success Response:

Code: 200 - OK

Body:
{
  "contract": {
    "timestamp": Int,
    "storage": {
      String : String
      String : String
      ...
    },
    "methods": [string,...],
    "script": String (code)
  },
  "address": String (Address)
}

Transactions

All Transactions in Block

Get the list of transactions in a block by providing the block index

URL: /transactions/:blockIdx

Success Response:

Code: 200 - OK

Body:
[ {
    "header" : TransactionHeader,
    "signature" : String (Base64 Sha256 hash)
    "from" : String (Address),
    "fromPub" : String (ECDSA Public key fingerprint),
    "timestamp" : Timestamp (Unix Timestamp, Int64)
  },
  ...
]

Transaction by Block Index and Transaction Index

Get a specific transaction by proving the block index and transaction index of the transaction

URL: /transactions/:blockIdx/:transactionIdx

Success Response:

Code: 200 - OK

Body:
{
  "header" : TransactionHeader,
  "signature" : String (Base64 Sha256 hash)
  "from" : String (Address),
  "fromPub" : String (ECDSA Public key fingerprint),
  "timestamp" : Timestamp (Unix Timestamp, Int64)
}

JSON Values

Call transactions require the value types of arguments to the method being called as they are fields in the transaction header, and transaction headers must be signed with ECDSA. The values must be binary serialized in the specific format that an Uplink node expects such that the uplink node can validate the ECDSA signature provided by the SDK the transaction issuer is using.

VInt Int64             -- ^ Integral types
VFloat Double          -- ^ Floating types
VBool Bool             -- ^ Boolean value
VAddress Address       -- ^ Address
VAccount Address       -- ^ Account Address
VAsset Address         -- ^ Asset Address
VContract Address      -- ^ Contract Address
VMsg SafeString        -- ^ Msgs (ASCII)
VSig (SafeInt,SafeInt) -- ^ ESDSA Sig
VVoid                  -- ^ Void
VDateTime DateTime     -- ^ DateTime value
VTimeDelta TimeDelta   -- ^ TimeDelta value
VState Label           -- ^ Named state label

where
  SafeInt              -- Int value not exceeding 512 bytes
  SafeString           -- String value not exceeding 10 kilobytes

Encoding:

All FCL values are encoded as a sequence of big-endian bytestrings. The format of all serialized bytestrings is a single signed-char byte denoting the constructor of the value, and then the serialized raw value/s that make up the components of the value.

(VInt n) - 9 bytes

<unsigned char>      : 0       [1 byte]
<unsigned long long> : n       [8 bytes]
(VFloat f) - 9 bytes

<unsigned char>      : 2       [1 byte]
<double>             : f       [8 bytes]
(VBool b) - 2 bytes

<unsigned char>      : 4       [1 byte]
<_Bool (C99)>        : b       [1 byte]
(VAddress a) - 33 bytes

<unsigned char>      : 5       [1 byte]
<char[]>             : a       [32 bytes]
(VAccount a) - 33 bytes

<unsigned char>      : 6       [1 byte]
<char[]>             : a       [32 bytes]
(VAsset a) - 33 bytes

<unsigned char>      : 7       [1 byte]
<char[]>             : a       [32 bytes]
(VContract c) - 33 bytes

<unsigned char>      : 8       [1 byte]
<char[]>             : c       [32 bytes]
(VMsg (SafeString s)) - [3 - 100003 bytes]

<unsigned char>      : 9       [1 byte]
<unsigned short> : len(s)  [2 bytes]
<char[]>             : s       [len(s) bytes]
(VSig (SafeInt r, SafeInt s)) - [1029 bytes]

<unsigned char>      : 10                 [1 byte]
-- Encoding of 'r'
<unsigned char>      : signOf(r)          [1 byte]
<unsigned char>      : numBytes(s)        [2 byte]
-- Big Endian encoding of 's', numBytes(n) bytes (maximum 512)
<unsigned char>      : byteNminus1        [1 byte]
...
<unsigned char>      : byte1              [1 byte]
<unsigned char>      : byte0              [1 byte]

-- Encoding of 's'
<unsigned char>      : signOf(s)          [1 byte]
<unsigned char>      : numBytes(s)        [2 byte]
-- Big Endian encoding of 's', numBytes(n) bytes (maximum 512)
<unsigned char>      : byteNminus1        [1 byte]
...
<unsigned char>      : byte1              [1 byte]
<unsigned char>      : byte0              [1 byte]
(VVoid) - 1 byte

<unsigned char>      : 11      [1 byte]
(VDateTime (DateTime y mo d h m s z w)) - 513 bytes

<unsigned char>      : 12      [1 byte]
<unsigned long long> : y       [8 bytes]
<unsigned long long> : mo      [8 bytes]
<unsigned long long> : d       [8 bytes]
<unsigned long long> : h       [8 bytes]
<unsigned long long> : m       [8 bytes]
<unsigned long long> : s       [8 bytes]
<unsigned long long> : z       [8 bytes]
<unsigned long long> : w       [8 bytes]
(VTimeDelta (TimeDelta (Period y mo d) (Duration h m s ns)) - 449 bytes

<unsigned char>      : 13      [1 byte]
<unsigned long long> : y       [8 bytes]
<unsigned long long> : mo      [8 bytes]
<unsigned long long> : d       [8 bytes]
<unsigned long long> : h       [8 bytes]
<unsigned long long> : m       [8 bytes]
<unsigned long long> : s       [8 bytes]
<unsigned long long> : ns      [8 bytes]
(VUndefined) - 1 byte

<unsigned char>      : 15      [1 byte]

Transport Level Security

To run the RPC server using SSL, first generated a certificate. If you wish to use a self-signed certificate for testing run:

$ openssl genrsa -out key.pem 2048
$ openssl req -new -key key.pem -out certificate.csr
$ openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem