Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 192 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Peerplays Developer Docs

Loading...

API Reference

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Peerplays API Libraries

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Development Guides

Loading...

Loading...

Loading...

Loading...

The Cookbook

Loading...

Tools and Integrations

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Supporting & Reference Docs

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Peerplays Core API

Block API

Block API

get_blocks

Get signed blocks.

vector<optional<signed_block>> graphene::app::block_api::get_blocks(
    uint32_t block_num_from, 
    uint32_t block_num_to)const
  • block_num_from: The lowest block number

  • block_num_to: The highest block number

A list of signed blocks from block_num_from to block_num_to

PeerID

Generic Sidechain Docs

Low Level Designs

This section contains pages that describe low level design

Listeners

subscribe_to_market

Subscribe a listener to a betting market.

  • updateListener: An object of type updateListener.

  • 1.3.0: Start version.

  • 1.3.19: End version.

unsubscribe_from_market

Unsubscribe a listener from a betting market.

  • updateListener: An object of type updateListener.

  • 1.3.0: Start version.

  • 1.3.19: End version.

Deployment to AWS ECS

Building the Docker Images

PeerID Backend

PeerID GUI

Apis.instance().db_api().exec( "subscribe_to_market", [updateListener, "1.3.0", "1.3.19"])
Apis.instance().db_api().exec( "unsubscribe_from_market", [updateListener, "1.3.0", "1.3.19"])

Network Broadcast API

The network broadcast API is available from the full node via web-sockets.

Transactions

broadcast_transaction

Broadcast a transaction to the network.

The transaction will be checked for validity in the local database prior to broadcasting. If it fails to apply locally, an error will be thrown and the transaction will not be broadcast

void graphene::app::network_broadcast_api::broadcast_transaction(
    const precomputable_transaction &trx)
  • trx: The transaction to broadcast

broadcast_transaction_with_callback

This version of broadcast transaction registers a callback method that will be called when the transaction is included into a block. The callback method includes the transaction id, block number, and transaction number in the block.

void graphene::app::network_broadcast_api::broadcast_transaction_with_callback(
    confirmation_callback cb, 
    const precomputable_transaction &trx)
  • cb: the callback method

  • trx: the transaction

Block

broadcast_block

Broadcast a signed block to the network.

void graphene::app::network_broadcast_api::broadcast_block(
    const signed_block &block)
  • block: The signed block to broadcast.

Orders API

Orders API

get_grouped_limit_orders

Get grouped limit orders in given market.

vector<limit_order_group> graphene::app::orders_api::get_grouped_limit_orders(
    std::string base_asset, 
    std::string quote_asset, 
    uint16_t group, 
    optional<price> start, 
    uint32_t limit)const
  • base_asset: ID or symbol of asset being sold

  • quote_asset: ID or symbol of asset being purchased

  • group: Maximum price diff within each order group, have to be one of configured values

  • start: Optional price to indicate the first order group to retrieve

  • limit: Maximum number of order groups to retrieve (must not exceed 101)

The grouped limit orders, ordered from best offered price to the worst.

Python Peerplays

Introduction

Its the Python library for communicating with the Peerplays blockchain.

The code is maintained at https://gitlab.com/PBSA/PeerplaysIO/tools-libs/python-peerplays

Ids

1.2.x : accounts

1.3.x : assets

Notes

def transfer(self, to, amount, asset, memo="", account=None, **kwargs):

p.rpc.get_account_balances("jemshid", [])

p.rpc.get_global_properties

private-key = ["TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]

Installation

The python-peerplays library has following dependencies. Make sure that the above dependencies are installed, if not install with:

sudo apt-get install python3-dev build-essential libssl-dev\
 libffi-dev libxml2-dev libxslt1-dev zlib1g-dev

Now install python-peerplays as follows:

 pip install peerplays

Ipython is a rich interactive python command shell. It's recommended for trying out python-peerplays library. It can be installed with

pip install ipython

In case Python 2.7 is the default Python for your machine, repalce

pip with pip3

python with python3

ipython with ipython3

Ipython shell can be started with the command

ipython

To work with the latest development version of python-peerplays

git clone [email protected]:PBSA/PeerplaysIO/tools-libs/python-peerplays.git

cd python-peerplays

git checkout develop

Creating a Peerplays Wallet

All these experiments and examples are expected to be tried out in ipython command shell. Start the command shell with ipython

Node is the chain with which you wish to interact.

node = "wss://elizabeth.peerplays.download/api"

password = "password"

from peerplays import PeerPlays

p = PeerPlays(node)

To create a new wallet

p.newWallet(password)

Unlock the wallet

p.unlock(password)

Add private key / keys

p.wallet.addPrivateKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")

Additional Methods

p.wallet.unlocked() #returns True if wallet is unlocked. Wallet needs to be unlocked to perform operations on the blockchain.

p.wallet.getAccounts() #Lists all the accounts associated with the private key.

Random Number Generator

son-wallet-list_sons-lld

1. Purpose

The purpose of this document is to provide a low-level design for implementing list_sons wallet functionality.

2. Scope

The design requirement listed in this document will be limited to the SON Wallet functionality.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Sidechain Operator Node ( SONs )

More on SON Objects can be found at SON Objects and Operators

5. Proposed Design Change

Users should be able to list all the SON nodes on the blockchain.

They should be able to check the status of the SON which is provided by the son_status variable in the son_object.

They should be able to check the number of votes polled during the last cycle, which is provided by total_votes in son_object. This is changes in every maintenance interval.

For better UI, we can list the SONs based on their status i.e. Active SONs first, Inactive next, In_Maintenance next in that order.

We can even further extend the types of data with the information stored in son_statistics_object as well.

This can be done by introducing a new structure (son_info in the UML below) that can collate the information in database_api and send it to the wallet.

Bookie API

Sidechain Operator Node (SON) Development

Building the Docker Images
Storing Secrets in Amazon Parameter Store to use in ECS
Creating the Task Definition
Creating the Cluster
Creating the Service

Creating the Cluster

After creating the Task Definition, we can now create a Cluster.

Creating a Fargate Cluster

Select the Networking only cluster template.

Configure cluster

Enter the cluster name.

Networking

If you don't already have a VPC setup, it's good practice to create one.

An example VPC would have 4 subnets, 2 meant to be private, and 2 meant to be public.

Example:

CIDR block 10.0.0.0/16 Subnet 1: 10.0.0.0/24 Subnet 2: 10.0.1.0/24 Subnet 3: 10.0.2.0/24 Subnet 4: 10.0.3.0/24

You would then navigate to the VPC service and:

  1. Create route table for each of the two subnets chosen to be public facing and route 0.0.0.0/0 to the VPC's internet gateway.

  2. Create NAT gateways for the public facing subnets.

  3. Create route tables for the private subnets and add a 0.0.0.0/0 routes to the NAT gateways.

Authentication with PeerID

{ "result": { "expires": "<expiry date of the token>", "app_id": <your client ID>, "scope": <permissions granted by the user>, "token": "<access token for the user>", "refresh_token": "<refresh token for the user>" }, "status": 200 }

Note: Store the access token and refresh token like passwords.

OAuth Resource Owner Password Credentials flow Follow the below steps to get the access token using the OAuth Resource Owner Password Credentials flow:

  1. In your app, request for user's login credentials i.e. username or email ID and mobile or password and on your server, get an access token by making this request:

    POST https://peerid.peerplays.download/api/v1/auth/token ?login=<user's username or email ID> &password=<user's password> &mobile=<user's mobile number> &client_id=<your client ID>

    Either password or mobile parameters has to be passed in this request. If both are passed, the PeerID server validates both of them along with the login.

  2. We respond with a json-encoded access token. The response looks like this:

    { "result": { "expires": "<expiry date of the token>", "app_id": <your client ID>, "scope": <permissions granted by the user>, "token": "<access token for the user>", "refresh_token": "<refresh token for the user>" }, "status": 200 }

Sending access tokens

Once you have the user’s access token, your app can perform the permitted operations on behalf of the user on the Peerplays blockchain using the /api/v1/app/operations API. You have to pass the access token for the user in the Authorization header for this API like:

curl -H "Authorization: Bearer <access token>" https://peerid.peerplays.download/api/v1/app/operations

Note: The access token for one app cannot be used for another app.

Refreshing access token

New OAuth2 access tokens have expirations. Token-expiration periods vary in length, based on how and when the token was acquired. Tokens return an expires field indicating how long the token should last. However, you should build your applications in such a way that they are resilient to token authentication failures. In other words, an application capable of refreshing tokens should not need to know how long a token will live. Rather, it should be prepared to deal with the token becoming invalid at any time.

On seeing a 401 - Unauthorized error, an application should try to refresh the session if a refresh token is present. If the refresh fails, the application should re-prompt the end user with another authentication dialog via the standard OAuth 2 flow.

Generally, refresh tokens are used to extend the lifetime of a given authorization.

How to refresh:

To refresh a token, you need the refresh_token that you get in the response when you exchange your code for the token and the client ID and client secret. The following API returns the new access token:

POST https://peerid.peerplays.download/api/v1/auth/refreshtoken ?refresh_token=<refresh token for the user> &client_id=<your client ID> &client_secret=<your client secret>

The response will look like this:

{ "result": { "expires": "<expiry date of the token>", "app_id": <your client ID>, "scope": <permissions granted by the user>, "token": "<access token for the user>", "refresh_token": "<refresh token for the user>" }, "status": 200 }

git clone https://gitlab.com/PBSA/PeerplaysIO/tools-libs/peerid/peerid-backend.git -b support/docker
cd peerid-backend
docker build .
git clone https://gitlab.com/PBSA/PeerplaysIO/tools-libs/peerid/peerid-gui.git -b support/docker
cd peerid-gui

# edit the hompage in package.json with your DNS
vim package.json

# edit the .env with your variable values
vim .env

docker build . -f prod.Dockerfile

Infrastructure

The two ways of deployment are explained in the documents below:

Development

The following documents help to understand the requirements and authentication process of PeerID:

How does PeerID work without storing the keys ?

Introduction

With the implementation of Hierarchical Role based Permissions (HRP) in the Peerplays blockchain and the introduction of Custom Authorities, it is now possible to allow a proxy account to perform any operation on the Peerplays blockchain on your behalf. PeerID uses this feature to act as a proxy for any account that has provided the permission to perform a particular operations.

Custom Permissions

Every account that’s created on Peerplays has two default permissions by default.

  1. Owner

  2. Active

They have a parent-child relationship by default (owner being the parent). The implicit default permission linked to all operations is active, which sits one level below the owner permission within the hierarchy structure.

As a result, the active permission can do anything the owner permission can, except changing the keys associated with the owner.

With custom permissions, the permissions can be created separately and can be assigned the valid required authorities which satisfies the maximum recursion depth of the blockchain and the permissions can be linked to the operations through custom authorities which specifies the time validity of the permission over the operation. Any given permission of an account can be linked to multiple types of operations.

This gives applications flexibility to use the custom permission of an account and at the same time specify the validity.

Custom Authorities

In Peerplays (graphene-based chains), an authority consists of one or many entities that authorize an operation, such as transfers or bet placement, etc. Authority consists of one or several pairs of an account name with a weight. In order to obtain a valid transaction, the sum of the weights from signing the parties has to exceed the threshold as defined in the permissions.

Custom Authorities takes this concept to the next level with the help of Custom Permissions by storing the mapping between custom permissions and operations. The custom authorities specify the actual operation on the Peerplays blockchain that a proxy account can perform on behalf of another account and the validity of this arrangement.

Working of PeerID

As soon as an account is created or an existing Peerplays account logs in using PeerID, we create a custom permission for PeerID on the Peerplays blockchain to perform the custom_authority_create, custom_authority_update, custom_authority_delete operations on behalf of the account.

PeerID further allows developers to create an app which can request for additional permissions from the user. When the user joins the app by allowing the app to perform some operation on his behalf, PeerID creates a custom authority for the requested operation by using its own custom permission. This way, we don't have to store the user's keys anywhere.

Working of PeerID

Developer Documentation

Your gateway to comprehensive APIs, guides for common services, use case examples, resources, tools, and more. Developer documentation is all about empowering you to build on the Peerplays blockchain.

API Reference

This section explains about the different types of API calls involved in exchanges and gateways. The sample output for several API calls are also listed. The following APIs are explained in this section:

  1. Peerplays Core API

  2. Wallet API

  3. Bookie API

API Libraries

API Libraries plays an important role in communicating with Peerplays blockchain. This section explains about:

  1. Steps to install

  2. How to create an account?

  3. How to create a Peerplays wallet?

  4. NFT, Marketplace, and Role based Permission API

Click the below link to learn about the API Libraries in detail.

Development Guides

The guides in this section will describe about the User Issued Assets, types of permissions, a detailed explanation about NFTs, and finally about cost calculation. Click the link below to learn in detail.

The Cookbook

Peerplays community need some specialized work to accomplish the vision of the community. The work includes file encoding, file storage, content verifiers, and Content Delivery Network (CDN) gateways which are not covered directly by Peerplays but a system is created to complete these works in a decentralized way. Click the below link to learn in detail about the plan and process.

Tools & Integration

This section explains about important Authentication techniques and random numbers:

  1. Peer ID - Explain about Authentication and Requirement to create a Peer ID

  2. Random Number Generator (RNG) - Explain about RNG Generation process and API involved in getting a random number.

Reference Docs

This section contains needful documents which helps to provide details about any questions that arise during learning and experimenting with Peerplays applications.

The topics under Supporting & Reference Documents are listed below:

  1. Peerplays Development FAQs

  2. Sidechain Operator Node (SON) Development

  3. Peerplays DEX Development

  4. SPK Network

  5. NFT Development

  6. Operation IDs List

  7. Sidechain Flow Diagram (HIVE coin)

  8. Sidechain Flow Diagram (Bitcoin)

Workflow

The workflow section provides a step by step approach followed in the Peerplays development process. Click below to learn in details about the nature of workflow involved in developing any application.

Other Documentation

There are different types of documents available to reduce the cost around time and helps in landing to specific topics. Use the below links to navigate to your desired page.

  1. Peerplays Public Docs Portal - Click to land in Public documentation portal.

  2. - Click to gather extensive knowledge about Peerplays.

  3. - Click to understand the operation of Peerplays node.

Asset API

Asset API

get_asset_holders

Get asset holders for a specific asset.

  • asset: The specific asset id or symbol

  • start: The start index

  • limit: Maximum limit must not exceed 100

A list of asset holders for the specified asset.

get_all_asset_holders

Get all asset holders.

A list of all asset holders.

Network Nodes API

The network node API is available from the full node via web-sockets.

Obtain Network Information

get_info

Return general network information, such as p2p port.

get_connected_peers

Get status of all current connections to peers.

get_potential_peers

Return list of potential peers.

get_advanced_node_parameters

Get advanced node parameters, such as desired and max number of connections.

Change Network Settings

add_node

Connect to a new peer

  • ep: The IP/Port of the peer to connect to

set_advanced_node_parameters

Set advanced node parameters, such as desired and max number of connections.

  • params: a JSON object containing the name/value pairs for the parameters to set

Blockchain Inspection

Blockchain Inspection

get_block

Returns info about a specified block.

  • num: height of the block to retrieve

Info about the block, or null if not found.

get_account_count

Returns the number of accounts registered on the blockchain.

The number of registered accounts

get_global_properties

Returns the block chain’s slowly-changing settings.

This object contains all of the properties of the blockchain that are fixed or that change only once per maintenance interval (daily) such as the current list of witnesses, committee_members, block interval, etc.

See for frequently changing properties.

The global properties.

get_dynamic_global_properties

Returns the block chain’s rapidly-changing properties. The returned object contains information that changes every block interval such as the head block number, the next witness, etc. See for less-frequently changing properties.

The dynamic global properties.

get_object

Returns the blockchain object corresponding to the given id.

This generic function can be used to retrieve any object from the blockchain that is assigned an ID. Certain types of objects have specialized convenience functions to return their objects e.g., assets have , accounts have , but this function will work for any object.

  • id: the id of the object to return.

The requested object.

General Calls

General Calls

help

Returns a list of all commands supported by the wallet API.

This lists each command, along with its arguments and return types. For more detailed help on a single command, use .

A multi-line string suitable for displaying on a terminal.

gethelp

Returns detailed help on a single API command.

  • method: the name of the API command you want help with

A multi-line string suitable for displaying on a terminal.

info

Returns info about head block, chain_id, maintenance, participation, current active witnesses and committee members.

Runtime info about the blockchain

about

Returns info such as client version, git version of graphene/fc, version of boost, openssl etc.

Compile time info and client and dependencies versions.

network_add_nodes

nodes: Nodes to be added.

network_get_connected_peers

List of connected peers.

Marketplace API

Operations

Create Offer

For example

Bid

For example

Cancel Offer

For example

Calls for info

Additional Info

For examples, refer to tests/test_market_place.py

Storing Secrets in Amazon Parameter Store to use in ECS

One way to pass secrets and variables securely to containers in AWS is to use Parameter Store. Navigate to the AWS Systems Manager service to get started.

Parameter Store

Create Parameter

  1. Enter a name or path for the parameter.

  2. Optionally add a description.

  3. Select the tier to use.

  4. Select the type. (we will choose SecureString.)

  5. Select the KMS key source which is what will encrypt the SecureString.

  6. Enter the value for the parameter.

Creating a Role and policy for ECS in IAM

In order for the containers in our Task Definition to get parameters, we need to enable KMS decrypt and SSM get parameter permissions. Navigate to IAM to get started.

Create Policy

Create a policy with permissions for KMS and SSM:

Create Role

  1. Choose the service Elastic Container Service

  2. Select the use case as Elastic Container Service Task

  3. Attach the policy created to read secrets from Parameter Store.

  4. Enter a role name.

  5. Enter a role description.

btc-address-scripting-mechanism

Purpose

This doc describes the required changes to Bitcoin multisignature wallet scripting mechanism (previously described in Multisignature wallet LLD).

Scope

TODO

Process Overview

SONs are expected to be co-signatories for the funds stored on PW. Each SON has a public key on Bitcoin (secp256k1) and the weight of its signature.

This is executed on Bitcoin blockchain with the following script:

<pubkey1> OP_CHECKSIG

OP_IF

<voting_weight1>

OP_ELSE

0

OP_ENDIF

OP_SWAP

<pubkey2> OP_CHECKSIG

OP_IF

<voting_weight2>

OP_ADD

OP_ENDIF

...

OP_SWAP

<pubkeyN-1> OP_CHECKSIG

OP_IF

<voting_weightN-1>

OP_ADD

OP_ENDIF

OP_SWAP

<pubkeyN> OP_CHECKSIG

OP_IF

<voting_weightN>

OP_ADD

OP_ENDIF

<two_thirds_of_total_voting_weight>

OP_GREATERTHAN

The point of the script is that each SON has a weight (sum of votes for SON that is set at maintenance). Depending on the cumulative weight of votes a decision is made on whether the transfer is to be executed. For the transfer to happen the sum of weights in the script must be >= 2/3 + 1 from the number of current active SON weights.

Since the addresses depend on weights, and weights in turn depend on balances, on most occasions the deposit addresses will be re-generated after maintenance. There are two ways to handle this situation:

  1. All pre-maintenance are to be considered invalid after maintenance.

  2. Consider the pre-maintenance composition of SONs and their weights trusted post-maintenance. If the composition of SONs doesn't change, but their weights do, SON members are to be allowed to process the transaction in accordance with their pre-maintenance weights.

We can change the ranking upon the first transaction related to PW/SONs takes place. This is further discussed here :

generic-sidechain-withdrawal-hld

Objective

This document is intended to outline generic design of withdrawal handling by Peerplays sidechain operating node. This interface will be extended to meet various other integrations.

Sidechain operating node will monitor Peerplays network for events of interest, namely transfer of Peerplays tokens to a shared SON account. When transfer happens, sidechain will process it, in order to pick up information needed to handle it. Handling withdrawals will create sidechain transaction, transferring certain amount of sidechain currency to the user who made the payment to the hared SON account. This amount will match the amount of Peerplays tokens by predefined exchange rate.

Assumptions

  • Peerplays SON network is able to transfer assets on sidechain networks, in order to send assets to a user account. E.g. Peerplays SONs network has control over an multi-signature account on Bitcoin, Ethereum, EOS network which holds ballance of sidechain currency and is able to transfer them to the sidechain user accounts.

  • Peerplays SON network have dedicated account on every supported sidechain. This address/account is a multi-signature account or script or smart contract, or any other entity supported by a target sidechain, which is able to send assets to users. This is the address where SON network will keep its sidechain asset ballance.

  • Sidechain operating node has access to assets exchange rate list, containing exchange rates for every asset on every supported sidechain network. This list should be updateable by Peerplays network administrators.

  • Sidechain operating node has access to user accounts mapping list, containing user addresses on supported sidechains. Key value in this mapping is user’s Peerplays account. E.g. [PeerplaysAccount, BitcoinAccount, EthereumAccount, …]. All sidechain accounts should be created by user (e.g. user can enter them during registration as a Peerplays user). Account creation on target sidechain should not be handled by Peerplays, because of increased risk of handling their private keys. This list should be updateable by user.

Block diagram

Link to file

Description

  • The withdrawal is initiated by user, by transfering Peerplays core asset to SON shared account.

  • As described in , when event of interest, transfer to a certain address on a target sidechain occurs, a sidechain handler will process it, and save the event data into Peerplays network for further processing.

  • Sidechain handler will identify user depositing funds, by searching transaction’s source address in user accounts mapping list, in order to find which Peerplays network address matches sidechain transaction source address. Peerplays network will transfer assets to this address (target address).

  • Sidechain handler will get the exchange rate from Exchange rate list, in order to calculate exact amount that needs to be transfered to the target address.

  • SONs will synchronize between them selves, by exchanging information about new transaction on Peerplays network and information about transfer that needs to be executed on sidechain network. Once all active SONs have same information about transaction, randomly selected SON will create transaction and start singing process. Source address of this transfer will be SONs controlled account for transferring sidechain assets to users.

  • When first signature is added to transaction, signed transaction will be sent through SONs network, so that other SONs can sign it. Depending on a sidechain features, at least 8 SONs needs to sign this transaction. We can also go with SONs with at least 2/3 of total weight signature, if that's supported by the sidechain. Last SON signing transaction will broadcast it to the network. Tutorial on how to use multisig in Bitshares is here:

  • All sidechain specific functionalities will be implemented in sidechain handler.

  • All general functionalities will be implemented in sidechain handler base class.

Sequence diagram

Link to file

Same sequence diagram applies for all sidechain handlers. It shows interactions between components in a single sidechain handler.

Wallet API

The wallet (cli_wallet) requires a running full node to connect to because it does not offer P2P or blockchain capabilities directly.

If you have not set up your wallet yet, you can find more information here: .

Functional Specs

Deployment on a Linux Serve
Deployment to AWS ECS
How does PeerID work without storing the keys ?
Authentication with PeerID
Brain Storming
Software Requirements
vector<account_asset_balance> graphene::app::asset_api::get_asset_holders(
    std::string asset, 
    uint32_t start, 
    uint32_t limit)const
vector<asset_holders> graphene::app::asset_api::get_all_asset_holders()const
fc::variant_object graphene::app::network_node_api:get_info()const
std::vector<net::peer_status> graphene::app::network_node_api::get_connected_peers()const
std::vector<net::potential_peer_record> graphene::app::network_node_api::get_potential_peers()const
fc::variant_object graphene::app::network_node_api::get_advanced_node_parameters()const
void graphene::app::network_node_api::add_node(
    const fc::ip::endpoint &ep)
void graphene::app::network_node_api::set_advanced_node_parameters(
    const fc::variant_object &params)
p.create_offer(
    item_ids,                  # list of items
    issuer_id_or_name,
    minimum_price,             # asset type
    maximum_price,             # asset type
    buying_item,               # bool
    offer_expiration_date,     # "2020-09-18T11:05:39"
    memo=None,                 # optional
    )
p.create_offer(["1.31.5"], "1.2.9", {"amount":5,"asset_id":"1.3.0"}, {"amount":15,"asset_id":"1.3.0"}, False, "2030-09-18T11:05:39", "")
p.create_bid(
    bidder_account_id_or_name,
    bid_price,                     # asset
    offer_id,                      # offer_id type, 1.29.x
    )
p.create_bid("1.2.10", {"amount":8,"asset_id":"1.3.0"}, offer["id"])
p.cancel_offer(
    issuer_account_id_or_name,
    offer_id,                     # offer_id type, 1.29.x
    )
p.cancel_offer("1.2.9", offer["id"])
p.rpc.list_offers(lower_id, limit)   # limt is number of entries requested as integer
p.rpc.list_sell_offers(lower_id, limit)
p.rpc.list_buy_offers(lower_id, limit)
p.rpc.list_offer_history(lower_id, limit)
p.rpc.get_offers_by_issuer(lower_id, issuer_account_id, limit)
p.rpc.get_offers_by_item(lower_id, nft_id_type_item, limit)
p.rpc.get_offer_history_by_issuer(lower_id, issuer_account_id, limit)
p.rpc.get_offer_history_by_item(lower_id, item, limit)
p.rpc.get_offer_history_by_bidder(lower_id, bidder_account_id, limit)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt",
                "ssm:GetParameters"
            ],
            "Resource": [
                "arn:aws:kms:<aws-region>:<account-id>:key/<key-id>",
                "arn:aws:ssm:<aws-region>:<account-id>:parameter/<parameter>"
            ]
        }
    ]
}
optional<signed_block_with_info> graphene::wallet::wallet_api::get_block(
    uint32_t num)
uint64_t graphene::wallet::wallet_api::get_account_count()const
global_property_object graphene::wallet::wallet_api::get_global_properties()const
dynamic_global_property_object graphene::wallet::wallet_api::get_dynamic_global_properties()const
variant graphene::wallet::wallet_api::get_object(
    object_id_type id)const
get_dynamic_global_properties()
get_global_properties()
get_asset()
get_account()
string graphene::wallet::wallet_api::help()const
string graphene::wallet::wallet_api::gethelp(
    const string &method)const
variant graphene::wallet::wallet_api::info()
variant_object graphene::wallet::wallet_api::about()const
void graphene::wallet::wallet_api::network_add_nodes(
    const vector<string> &nodes)
vector<variant> graphene::wallet::wallet_api::network_get_connected_peers()
gethelp()
Functional Specification - SONs switchover scenarios#SONsswitchoverscenarios-6.Scenarios
draw.io
https://drive.google.com/file/d/1qSWvcxfWVEwJV2nZA-xTApTSi5rH_1uv/view?usp=sharing
Generic Sidechain High Level Design
https://github.com/bitshares/bitshares1-core/wiki/multisig
draw.io
https://drive.google.com/file/d/17kbez7C1Djaj-2AgyEzQ1Z-5CrSZ5wZE/view?usp=sharing

bitcoin-deposit-handling-lld

Objective

This document is intended to outline generic design of a Bitcoin deposit handler, a component used for monitoring and processing deposits from a Bitcoin network.

For general information on deposit handlers, read: Generic Sidechain Deposit HLD

Asumptions

  • Peerplays SON network is able to control (transfer or create) assets on Peerplays network - FULFILLED

  • Peerplays SON network have full control over address/account on Bitcoin sidechain - FULFILLED (multisig addresses)

  • Sidechain operating node has access to assets exchange rate list, containing exchange rates for every asset on every supported sidechain network - FULFILLED For Bitcoin, exchange rate is fixed 1 BTC = 1 PPY

  • Sidechain operating node has access to user accounts mapping list, containing user addresses on supported sidechains - FULLFILLED

Block diagram

Link to draw.io file

https://drive.google.com/file/d/14HFGLqD8IV3ics1ojFcZ2xC6hRtFXLck/view?usp=sharing

Description

  • Deposit process is initiated by sending BTC to a Bitcoin address which is registered as a sidechain user address for deposits

  • Bitcoin listener will pick up this transaction

  • Bitcoin sidechain handler will create sidechain_event_data data structure, with the information about transaction, and pass it to the sidechain_event_data_received

  • sidechain_event_data_received will create a proposal for creating deposit descriptor object son_wallet_deposit_object

  • When proposal is approved, object will be created, or if it is already created by another SON, it will be confirmed

  • Scheduled SON will start processing withdrawals by creating Bitcoin transaction for sending funds from Bitcoin address which is registered as a sidechain user address for deposits to primary wallet (Bitcoin multisig address controlled by active SONs)

  • Bitcoin transaction will be signed and sent to Bitcoin node

  • User will receive Peerplays core asset matching the amount of deposited BTC

  • Scheduled SON will mark son_wallet_deposit_object as processed

son-de-register-proposals-lld

1. Purpose

The purpose of this document is to provide low-level design for SON Deregister proposals by a witness and how we can extend these in the future.

2. Scope

The design requirement listed in this document will be limited to the node management of SONs.

The document will also outline the way we can use the proposals related to SON management in the future.

The document will also outline the new data structures required to validate, raise and approve proposals efficiently.

The document will only outline the design from the point where a SON is down for more than N Hours ( N = 12 Currently ).

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Graphene Proposals

All the info related to proposals can be found at https://github.com/peerplays-network/peerplays/wiki/Proposal-Mechanism

5. Deregistering SON

According to the functional requirements of SON, if a SON is down for more than 12 hours, it should be deregistered from the network.

And for this to happen a witness has to raise a proposal that removes the SON from the network.

This has to happen if and only if there is no dependency on the SON for Bitcoin side operations. But this is out of the scope of this document.

All the statistics including the timestamp for when a SON is down is stored in son_statistics_object.

So when a witness detects that for any in_maintenance SON the current_time is greater by 12 hours than its last down timestamp, a witness proposal is raised.

The proposal will have a lifetime of 3 complete witness cycles so as to allow sufficient time for approval.

A new proposal object son_proposal_object(And its indexes) is introduced to fetch the proposals that are only related to SONs faster.

These proposals can even be used by other SONs in the future for raising proposals on the network.

i.e. The proposals can be used for Bitcoin-related proposals, to notify various events on the network, etc

  A new type of operation can be created to suit the scenarios we want to handle and the operations can be put into the proposals for approval.

All the new data structures and helper functions can be found in the UML diagram below.

refund-btc-mechanism

1. Purpose

The purpose of this document is to outline the steps required by a witness to create a proposal to refund the BTC deposited when more than 1/3rd SONs were down/inactive.

2. Scope

The design requirement listed in this document will be limited to the refund deposited BTC functionality of the SON – other coins should be handled differently if needed. This will outline the required steps that will be performed by the witness nodes to create a proposal to refund the BTC in the Peerplays blockchain. Also outlined here will be the sequence in which the required steps will be performed including:

  • any interactions with the user.

  • validations to ensure complete and accurate information gathering.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses. As per the current implementation of Sidechain, a multisig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multisig bitcoin address and will be required to sign any withdrawal transaction. When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multisig bitcoin address and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Process Overview

Described here is the design for refunding the BTC that was deposited on the Bitcoin Blockchain when more than 1/3rd SONs were inactive in the Peerplays blockchain.

5. Context

There can be a situation where more than 1/3rd of the SONs are down and a user deposits BTC to his account but it's not credited to his account. The ideal way to deal with such a situation is to create smart contracts (HTLC) to refund the BTC back to the user. In the absence of smart contracts, the below mentioned implementations have been suggested.

6. Implementations Suggested

  1. This can be handled by the witness nodes. Witnesses can't sign any transaction related to BTC sidechain since that is the responsibility of the SONs but they should be able to create a proposal to refund the BTC when the SONs were down and the SONs should be able to ratify this proposal once they are online. This way, the BTC of the users who deposited it when the SONs were down won't be lost and instead refunded. This proposal can be created on-chain or manually by the witnesses. a. We just need to The implementation for a manual proposal by witnesses will be much lower than any other implementation suggested above. b. In an on-chain implementation, the witnesses will have to run a bitcoin instance on their node and the peerplays code will include a bitcoin listener (already implemented in sidechain) which will listen to the changes on the bitcoin blockchain and will keep track of SONs' inactivity. As soon as more than 1/3rd of the SONs become inactive, it will check for any deposits made to the Bitcoin wallet and create a proposal to refund it. This proposal can be signed by the SONs and the amount can be refunded.

  2. During the period when more than 1/3rd of the SONs are down, the active SONs should either create the proposal for depositing pBTC to the users or to simply refund the BTC deposited by the user and when the rest of the SONs become active again, they should be able to verify it and sign the proposal. In this case, the time taken for the depositing the pBTC to the user's account may be more than 3 hours.

  3. When the SONs become active after a period of inactivity, they should first check for any missed transactions on the Bitcoin blockchain and refund the BTC to the user that was deposited during the inactivity.

7. Flow Diagram

To be done on the basis of the implementation chosen.

wallet-commands-for-son

1. Purpose

The purpose of this document is to provide the design for the commands to be added to the CLI Wallet for SONs.

2. Scope

The design requirement listed in this document will be limited to the commands to be added to the CLI Wallet. This will outline the commands required to be added and their implementation. Also outlined here will be the sequence in which the required steps will be performed including:

  • any interactions with the user.

  • validations to ensure complete and accurate information gathering.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses. As per the current implementation of Sidechain, a multisig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multisig bitcoin address and will be required to sign any withdrawal transaction. When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multisig bitcoin address and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Process Overview

Described here is the design for commands to be added to the CLI Wallet for adding/removing SON, voting for SON, etc.

5. Context

The following commands will have to be added in the CLI wallet and new APIs created for the same to allow the users to use the SON functionality:

a. create_son(string owner_account, string url, bool broadcast) This command creates a transaction to create a new SON. The parameters required are: owner_account: account name which has to be registered as an SON, url: published url where the SON has published his details and his marketing pitch and broadcast: whether to broadcast this transaction or not (default: false).

b. vote_for_son(string voting_account, string son_account, bool approve, bool broadcast) This command creates a transaction to vote for an SON. The parameters required are: voting_account: account name which is voting son_account: account name of the SON to whom the votes are being cast approve: whether the votes are being cast or withdrawn (default: false) broadcast: whether to broadcast this transaction or not (default: false)

c. get_son(string owner_account) Command to get the details of an SON. The parameters required are: owner_account: account name of the SON

d. update_son(string son_name, string url, string bitcoin_signing_key, bool broadcast) This command creates a transaction to update the SON. The parameters required are: son_name: The name of the SON to be updated url: published url where the SON has published his details and his marketing pitch to be updated bitcoin_signing_key: bitcoin transaction signing key of the SON to be updated broadcast: whether to broadcast this transaction or not (default: false)

e. update_son_votes(string voting_account, std::vector<std::string> sons_to_approve, std::vector<std::string> sons_to_reject, uint16_t desired_number_of_sons, bool broadcast) This command creates a transaction to update the votes for SONs. The parameters required are: voting_account: The account name which is voting sons_to_approve: The SONs to which the votes have to be casted sons_to_reject: The SONs from which the votes have to be removed desired_number_of_sons: The total number of SONs that the user wants to vote for broadcast: whether to broadcast this transaction or not (default: false)

f. list_sons(string& lowerbound, uint32 limit) Command to list the SONs starting from a lowerbound account id. lowerbound: The account id to start searching SONs from limit: The max number of SONs to be returned

g. claim_registered_son(const std::string& son_name) Command to save the private keys of the registered SON in the wallet permanently after the registration of SON is successful. The SON should have been created from the same CLI wallet. son_name: The name of the SON whose private keys are being saved in the wallet.

h. remove_son(string owner_account, bool broadcast) This command creates the transaction for remove_son_operation. The parameters required are: owner_account: The account name of the witness to be removed. broadcast: whether to broadcast this transaction or not (default: false)

i. list_active_sons(string& lowerbound, uint32 limit)

Command to list the SONs that are active currently.

We can use global_property_object::active_sons to retrieve the currently active SONs list.

lowerbound: The account id to start searching SONs from limit: The max number of SONs to be returned

The following commands will have to be updated in the CLI wallet and in the existing APIs to add the functionality related to SONs:

a. get_global_properties() This command returns the global properties of the blockchain such as head_block_num, head_block_id, next_maintenance_time, active_witnesses, active_committee_members, etc. This should be modified to provide the active_sons as well.

b. resync() method The resync method in the wallet.cpp file updates the wallet_data annotations e.g. wallet has been restarted and was not notified of the events while it was down.

Creating an Account

There are two ways to create an account.

  1. With Python-Peerplays: If you already have an account, it can be used to create another account.

  2. With the Faucet: To create an account without an existing account.

The Python-Peerplays Method

You need a funded account to create additional accounts. The funded account should be upgraded to create new accounts. To upgrade an account

p.upgrade_account(account="account_name")

Once the account is upgraded

p.create_account(account_name="new_account_name", registrar="the_upgraded_account", owner_key='TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV', active_key='TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV', memo_key='TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV')

The Faucet Method

url = https://mint-faucet.peerplays.download/

params = {'account': {
    'name': 'new_account_name',
    'owner_key': 'TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
    'active_key': 'TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
    'memo_key': 'TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
    'refcode': '',
    'referrer': ''}}

requests.post(url, json=params)

Additional Methods

p.transfer(to, amount, asset, memo="", account=None)

Creating the Service

Once we have created a Cluster, we can create a service inside it.

Configure Service

  1. Choose a Launch Type. (In this case we will be using FARGATE).

  2. Select a Task Definition and revision.

  3. Select the platform version.

  4. Select a cluster.

  5. Create a name for the service.

  6. Select the service type (in this case we will be using REPLICA).

  7. Enter the number of tasks that the service should try to keep running.

  8. Enter the desired value for the minimum and maximum healthy percent.

Deployments

Select either the Rolling update or Blue/green deployment.

Task Placement

Select a placement strategy from the placement templates.

Configure network

VPC and security groups

  1. Select your Cluster VPC.

  2. Select your desired subnets.

  3. Attach security groups.

  4. Attach a Load Balancer

Set Auto Scaling (optional)

Select Service Auto Scaling to set the cardinality of tasks and automatic task scaling policies.

bitcoin-withdrawal-handling-lld

Bitcoin Withdrawal Handling LLD

This document assumes that the multi-signature wallet is existing

Objective

This document is intended to outline generic design of a Bitcoin withdrawal handler, a component used for processing withdrawals to Bitcoin network.

For general information on deposit handlers, read: Generic Sidechain Withdrawal HLD

Asumptions

  • Peerplays SON network is able to transfer assets on Bitcoin network - FULFILLED

  • Peerplays SON network have dedicated account on Bitcoin sidechain - FULFILLED (multisig addresses)

  • Sidechain operating node has access to assets exchange rate list, containing exchange rates for every asset on every supported sidechain network - FULFILLED For Bitcoin, exchange rate is fixed 1 BTC = 1 PPY

  • Sidechain operating node has access to user accounts mapping list, containing user addresses on supported sidechains - FULLFILLED

Block diagram

Link to draw.io file

https://drive.google.com/file/d/1qSWvcxfWVEwJV2nZA-xTApTSi5rH_1uv/view?usp=sharing

Description

  • Withdrawal process is initiated by sending Peerplays core asser to a SON shared account

  • Peerplays listener will pick up this transaction

  • Peerplays sidechain handler will create sidechain_event_data data structure, with the information about transaction, and pass it to the sidechain_event_data_received

  • sidechain_event_data_received will create a proposal for creating withdrawal descriptor object - son_wallet_withdrawal_object

  • When proposal is approved, object will be created, or if it is already created by another SON, it will be confirmed

  • Scheduled SON will start processing withdrawals by creating Bitcoin transaction for sending funds from primary wallet (Bitcoin multisig address controlled by active SONs) to the a Bitcoin address which is registered as a sidechain user address for withdrawals

  • Bitcoin transaction will be signed and sent to Bitcoin node

  • Scheduled SON will mark son_wallet_withdrawal_object as processed

son-voting-lld

1. Purpose

The purpose of this document is to provide low-level design for SON Voting mechanism.

2. Scope

The design requirement listed in this document will be limited to the voting mechanism of the SON Objects.

The document will also outline the way a SON object can be voted.

The document will also outline how the votes are tallied at the maintenance interval.

The document will also outline how the top N SONs are updated during the maintenance interval.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Sidechain Operator Node ( SONs )

More on SON Objects can be found at SON Objects and Operators

5. How can SON be voted on

Users can vote for SONs in a similar way they vote for a witness.

A PeerPlays account updates his votes in 'account_object' via standard Graphene operation 'account_update_operation' (covered by 'account_object::account_options::num_witness' and 'account_object::account_options::votes' fields). wallet API has methods introduced for it: 'set_desired_witness_committee_son_member_count' (standard method, updated) and 'vote_for_son'.

Below is the sequence of how to vote for an SON.

6. Tallying Votes for SONs

At maintenance interval a 'vote_tally_helper::operator()' is called for each committee account on PeerPlays.

Votes for SON are added to 'database::_vote_tally_buffer', using 'vote_id' as an index from 'account_object::account_options::votes', and 'voting_stake' of the account as value.

In 'database::_son_count_histogram_buffer', using 'amount_son_members / 2' as an index, and 'voting_stake' of the account as value, the votes for a new number of top SONs are added.

Based on the above, the number of top SONs can only be odd, as during the calculation it is divided by 2, then multiplied by 2 and added + 1.

A method 'database::update_active_sons' is called to determine the actual number of top SONs (the order in which they are placed).

First, a calculation of votes for the number of top SONs is performed (step 2). 'stake_target' needs to be reached, which equals 1/2 of the 'voting_stake' (without considering the stakes of the votes for 0 SONs).

The data from 'database::_son_count_histogram_buffer' are orderly summed into a variable until it reaches 'stake_target'.

The index, at which the counting stops, will be multiplied by 2 and added + 1. The result of these operations will be the new number of top SONs.

New SONs are elected via 'database::sort_votable_objects` - a method to sort the witnesses and now SONs by the votes given to them by users.

A similar approach can be found in the witness voting tally code in perform_chain_maintenance.

CLI Wallet Setup
Account Calls
Asset Calls
Blockchain Inspection
General Calls
Governance
Privacy Mode
Trading Calls
Transaction Builder
Wallet Calls
SON Configuration
SON rewards
SON Voting and Consensus
SONs switchover scenarios
SON Status Operations & Monitoring
Proposals
SON Smart Contracts

Changes to Peerplaysjs-lib

Peerplaysjs-lib is a javascript library that provides an easy way to connect to the peerplays blockchain. This page reflects the changes that have to be made to the peerplaysjs-lib to support SONs.

Following changes have been made to the peerplaysjs-lib:

  1. ChainTypes.js

    1. Add the following missing object types to the object_type constant: son: 27, son_proposal: 28, son_wallet: 29, son_wallet_deposit: 30, son_wallet_withdraw: 31, sidechain_address: 32, sidechain_transaction: 33

    2. Add the following missing implementation object types to the impl_object_type constant: son_statistics: 24, son_schedule: 25

    3. Add the following missing operations in operations constant: son_create: 82, son_update: 83, son_delete: 84, son_heartbeat: 85, son_report_down: 86, son_maintenance: 87, son_wallet_recreate: 88, son_wallet_update: 89, son_wallet_deposit_create: 90, son_wallet_deposit_process: 91, son_wallet_withdraw_create: 92, son_wallet_withdraw_process: 93, sidechain_address_add: 94, sidechain_address_update: 95, sidechain_address_delete: 96, sidechain_transaction_create: 97, sidechain_transaction_sign: 98, sidechain_transaction_send: 99, sidechain_transaction_settle: 100

  2. operations.js 1. Add the following missing fee parameters:

    const son_create_operation_fee_parameters = new Serializer( 'son_create_operation_fee_parameters', { fee: uint64 } ); const son_update_operation_fee_parameters = new Serializer( 'son_update_operation_fee_parameters', { fee: uint64 } ); const son_delete_operation_fee_parameters = new Serializer( 'son_delete_operation_fee_parameters', { fee: uint64 } ); const son_heartbeat_operation_fee_parameters = new Serializer( 'son_heartbeat_operation_fee_parameters', { fee: uint64 } ); const son_report_down_operation_fee_parameters = new Serializer( 'son_report_down_operation_fee_parameters', { fee: uint64 } ); const son_maintenance_operation_fee_parameters = new Serializer( 'son_maintenance_operation_fee_parameters', { fee: uint64 } ); const son_wallet_recreate_operation_fee_parameters = new Serializer( 'son_wallet_recreate_operation_fee_parameters', { fee: uint64 } ); const son_wallet_update_operation_fee_parameters = new Serializer( 'son_wallet_update_operation_fee_parameters', { fee: uint64 } ); const son_wallet_deposit_create_operation_fee_parameters = new Serializer( 'son_wallet_deposit_create_operation_fee_parameters', { fee: uint64 } );

    const son_wallet_deposit_process_operation_fee_parameters = new Serializer( 'son_wallet_deposit_process_operation_fee_parameters', { fee: uint64 } );

    const son_wallet_withdraw_create_operation_fee_parameters = new Serializer( 'son_wallet_withdraw_create_operation_fee_parameters', { fee: uint64 } );

    const son_wallet_withdraw_process_operation_fee_parameters = new Serializer( 'son_wallet_withdraw_process_operation_fee_parameters', { fee: uint64 } ); const sidechain_address_add_operation_fee_parameters = new Serializer( 'sidechain_address_add_operation_fee_parameters', { fee: uint64 } );

    const sidechain_address_update_operation_fee_parameters = new Serializer( 'sidechain_address_update_operation_fee_parameters', { fee: uint64 } );

    const sidechain_address_delete_operation_fee_parameters = new Serializer( 'sidechain_address_delete_operation_fee_parameters', { fee: uint64 } );

    const sidechain_transaction_create_operation_fee_parameters = new Serializer( 'sidechain_transaction_create_operation_fee_parameters', { fee: uint64 } );

    const sidechain_transaction_sign_operation_fee_parameters = new Serializer( 'sidechain_transaction_sign_operation_fee_parameters', { fee: uint64 } );

    const sidechain_transaction_send_operation_fee_parameters = new Serializer( 'sidechain_transaction_send_operation_fee_parameters', { fee: uint64 } );

    const sidechain_transaction_settle_operation_fee_parameters = new Serializer( 'sidechain_transaction_settle_operation_fee_parameters', { fee: uint64 } );

    1. Add these fee parameters to the fee_parameters constant: son_create_operation_fee_parameters, son_update_operation_fee_parameters, son_delete_operation_fee_parameters, son_heartbeat_operation_fee_parameters, son_report_down_operation_fee_parameters, son_maintenance_operation_fee_parameters, son_wallet_recreate_operation_fee_parameters, son_wallet_update_operation_fee_parameters, son_wallet_deposit_create_operation_fee_parameters, son_wallet_deposit_process_operation_fee_parameters, son_wallet_withdraw_create_operation_fee_parameters, son_wallet_withdraw_process_operation_fee_parameters, sidechain_address_add_operation_fee_parameters, sidechain_address_update_operation_fee_parameters, sidechain_address_delete_operation_fee_parameters, sidechain_transaction_create_operation_fee_parameters, sidechain_transaction_sign_operation_fee_parameters, sidechain_transaction_send_operation_fee_parameters, sidechain_transaction_settle_operation_fee_parameters

    2. Add missing fields to parameter_extensions constant: gpos_period: optional(uint32), gpos_subperiod: optional(uint32), gpos_period_start: optional(uint32), gpos_vesting_lockin_period: optional(uint32), son_vesting_amount: optional(uint32), son_vesting_period: optional(uint32), son_pay_max: optional(uint32), son_pay_time: optional(uint32), son_deregister_time: optional(uint32), son_heartbeat_frequency: optional(uint32), son_down_time: optional(uint32), son_bitcoin_min_tx_confirmations: optional(uint16), son_account: optional(protocol_id_type('account')), btc_asset: optional(protocol_id_type('asset'))

    3. Add a new serializer for dormant_vesting_balance_initializer and add it to the constant vesting_policy_initializer: const dormant_vesting_policy_initializer = new Serializer('dormant_vesting_policy_initializer', {});

    4. Add 'son' to vesting_balance_type enum serializer: const vesting_balance_type = enumeration([ 'normal', 'gpos', 'son' ]);

    5. Add the following missing operation serializers: const sidechain_type = enumeration([ 'unknown', 'bitcoin', 'ethereum', 'eos', 'peerplays' ]);

      const son_create = new Serializer('son_create', { fee: asset, owner_account: protocol_id_type('account'), url: string, deposit: protocol_id_type('vesting_balance'), signing_key: public_key, sidechain_public_keys: map(sidechain_type, string), pay_vb: protocol_id_type('vesting_balance') });

      const son_update = new Serializer('son_update', { fee: asset, son_id: protocol_id_type('son'), owner_account: protocol_id_type('account'), new_url: optional(string), new_deposit: optional(protocol_id_type('vesting_balance')), new_signing_key: optional(public_key), new_sidechain_public_keys: optional(map(sidechain_type, string)), new_pay_vb: optional(protocol_id_type('vesting_balance')) });

      const son_delete = new Serializer('son_delete', { fee: asset, son_id: protocol_id_type('son'), payer: protocol_id_type('account'), owner_account: protocol_id_type('account') });

      const son_heartbeat = new Serializer('son_heartbeat', { fee: asset, son_id: protocol_id_type('son'), owner_account: protocol_id_type('account'), ts: time_point_sec });

      const son_report_down = new Serializer('son_report_down', { fee: asset, son_id: protocol_id_type('son'), payer: protocol_id_type('account'), down_ts: time_point_sec });

      const son_maintenance_request_type = enumeration([ 'request_maintenance', 'cancel_request_maintenance' ]);

      const son_maintenance = new Serializer('son_maintenance', { fee: asset, son_id: protocol_id_type('son'), owner_account: protocol_id_type('account'), request_type: son_maintenance_request_type });

      const son_info = new Serializer('son_info', { son_id: protocol_id_type('son'), weight: uint16, signing_key: public_key, sidechain_public_keys: map(sidechain_type, string) });

      const son_wallet_recreate = new Serializer('son_wallet_recreate', { fee: asset, payer: protocol_id_type('account'), sons: set(son_info) });

      const son_wallet_update = new Serializer('son_wallet_update', { fee: asset, payer: protocol_id_type('account'), son_wallet_id: protocol_id_type('son_wallet'), sidechain: sidechain_type, address: string });

      const son_wallet_deposit_create = new Serializer('son_wallet_deposit_create', { fee: asset, payer: protocol_id_type('account'), son_id: protocol_id_type('son'), timestamp: time_point_sec, block_num: uint32, sidechain: sidechain_type, sidechain_uid: string, sidechain_transaction_id: string, sidechain_from: string, sidechain_to: string, sidechain_currency: string, sidechain_amount: int64, peerplays_from: protocol_id_type('account'), peerplays_to: protocol_id_type('account'), peerplays_asset: asset });

      const son_wallet_deposit_process = new Serializer('son_wallet_deposit_process', { fee: asset, payer: protocol_id_type('account'), son_wallet_deposit_id: protocol_id_type('son_wallet_deposit') });

      const son_wallet_withdraw_create = new Serializer('son_wallet_withdraw_create', { fee: asset, payer: protocol_id_type('account'), son_id: protocol_id_type('son'), timestamp: time_point_sec, block_num: uint32, sidechain: sidechain_type, peerplays_uid: string, peerplays_transaction_id: string, peerplays_from: protocol_id_type('account'), peerplays_asset: asset, withdraw_sidechain: sidechain_type, withdraw_address: string, withdraw_currency: string, withdraw_amount: int64 });

      const son_wallet_withdraw_process = new Serializer('son_wallet_withdraw_process', { fee: asset, payer: protocol_id_type('account'), son_wallet_withdraw_id: protocol_id_type('son_wallet_withdraw') });

      const sidechain_address_add = new Serializer('sidechain_address_add', { fee: asset, payer: protocol_id_type('account'), sidechain_address_account: protocol_id_type('account'), sidechain: sidechain_type, deposit_public_key: string, deposit_address: string, deposit_address_data: string, withdraw_public_key: string, withdraw_address: string });

      const sidechain_address_update = new Serializer('sidechain_address_update', { fee: asset, payer: protocol_id_type('account'), sidechain_address_id: protocol_id_type('sidechain_address'), sidechain_address_account: protocol_id_type('account'), sidechain: sidechain_type, deposit_public_key: optional(string), deposit_address: optional(string), deposit_address_data: optional(string), withdraw_public_key: optional(string), withdraw_address: optional(string) });

      const sidechain_address_delete = new Serializer('sidechain_address_delete', { fee: asset, payer: protocol_id_type('account'), sidechain_address_id: protocol_id_type('sidechain_address'), sidechain_address_account: protocol_id_type('account'), sidechain: sidechain_type });

      const sidechain_transaction_create = new Serializer('sidechain_transaction_create', { fee: asset, payer: protocol_id_type('account'), sidechain: sidechain_type, object_id: protocol_id_type('object'), transaction: string, signers: set(son_info) });

      const sidechain_transaction_sign = new Serializer('sidechain_transaction_sign', { fee: asset, signer: protocol_id_type('son'), payer: protocol_id_type('account'), sidechain_transaction_id: protocol_id_type('sidechain_transaction'), signature: string });

      const sidechain_transaction_send = new Serializer('sidechain_transaction_send', { fee: asset, payer: protocol_id_type('account'), sidechain_transaction_id: protocol_id_type('sidechain_transaction'), signature: string });

      const sidechain_transaction_settle = new Serializer('sidechain_transaction_settle', { fee: asset, payer: protocol_id_type('account'), sidechain_transaction_id: protocol_id_type('sidechain_transaction') });

    6. Add the missing operations in st_operations: son_create, son_update, son_delete, son_heartbeat, son_report_down, son_maintenance, son_wallet_recreate, son_wallet_update, son_wallet_deposit_create, son_wallet_deposit_process, son_wallet_withdraw_create, son_wallet_withdraw_process, sidechain_address_add, sidechain_address_update, sidechain_address_delete, sidechain_transaction_create, sidechain_transaction_sign, sidechain_transaction_send, sidechain_transaction_settle

Peerplays API Libraries
Development Guides
The Cookbook
Supporting & Reference Docs
Development Workflow Docs

NFT API

API Calls for Non Fungible Tokens

Operations

Create NFT Meta

For example

Update NFT Meta

For example

Mint NFT

For example

Transfer NFT

For example

Approve Control over NFT

For example

Approve for all the tokens owned

For example

Info calls

p.rpc.nft_get_balance(owner)

p.rpc.nft_owner_of(token_id)

p.rpc.nft_get_approved(token_id)

p.rpc.nft_is_approved_for_all(owner, operator)

p.rpc.nft_get_name(nft_metadata_id)

p.rpc.nft_get_symbol(nft_metadata_id)

p.rpc.nft_get_token_uri(token_id)

p.rpc.nft_get_total_supply(nft_metadata_id)

p.rpc.nft_token_by_index(nft_metadata_id, token_idx)

p.rpc.nft_token_of_owner_by_index(nft_metadata_id, owner, token_idx)

p.rpc.nft_get_all_tokens()

p.rpc.nft_get_tokens_by_owner(owner)

Additional Info

For examples, refer to tests/test_nft.py

Creating the Task Definition

This article will be referencing the following repositories as the Docker image codebase:

In ECS, create a new Task Definition and choose the desired launch type compatibility (Fargate or EC2)

Attach the Task Role

Attach the task role created from .

Attach the Task Execution Role

This role is required by tasks to pull container images and publish container logs to Amazon CloudWatch on your behalf. You can use the default one created by Amazon.

Adjust the Task Size

We can assign total memory and CPU to the task. For PeerID, choose:

  • 2GB Task Memory (GB)

  • 1 vCPU Task CPU (vCPU)

Adding the Containers

Create two containers:

  • PeerID Backend

  • PeerID Frontend + Webserver (we will be using NGINX)

PeerID Backend

  1. Enter the container name.

  2. Enter the path to the Docker registry with the container Image.

  3. Enter 1024 for a soft limit for the memory.

  4. Enter 3000 tcp for the port mappings.

  5. Enter 756 CPU units.

  6. Tick the essential box.

  7. Enter /peerid-backend/docker-entrypoint.sh for the entry point.

  8. Enter npm,run,start for the command.

  9. Enter peerid-backend for the working directory.

  10. Enter the environment variables for PeerID Backend using ValueFrom and referencing the parameters from Systems Manager Parameter Store.

PeerID Frontend

  1. Enter the container name.

  2. Enter the path to the Docker registry with the container Image.

  3. Enter 256 for a soft limit for the memory.

  4. Enter 80 and 443 tcp for the port mappings.

  5. Enter 256 CPU units.

  6. Tick the essential box.

  7. Enter /docker-entrypoint.sh for the entry point.

  8. Enter nginx,-g,daemon off; for the command.

  9. Enter the environment variables for PeerID GUI using ValueFrom and referencing the values created from Systems Manager Parameter Store.

RNG API

Get a random number

bound: The upper limit for the random number.

A random number within the bound range.

TypeDefs

Declaration

Examples

Initialization in constructor

Updating seed on a new block

Getting a new random number

p.nft_metadata_create(
    owner_account_id_or_name,        # owner of nft meta
    name,                            # nft meta name
    symbol,                          # nft symbol
    base_uri,                        # nft uri
    is_transferable=True,
    is_sellable=True,
    )
p.nft_metadata_create("1.2.7", self.nameMetadata, self.nameMetadata, self.nameMetadata, revenue_partner="1.2.8", revenue_split=300, is_sellable=False, is_transferable=False)
p.nft_metadata_update(
    owner_account_id_or_name,
    nft_metadata_id,
    name,
    symbol,
    base_uri,
    is_transferable=True,
    is_sellable=True,
    )
p.nft_metadata_update("1.2.7", "1.30.11", self.nameMetadata + "m", self.nameMetadata + "m", self.nameMetadata + "m", "1.2.9", 400, True, True)
p.nft_mint(
    metadata_owner_account_id_or_name,
    metadata_id, 
    owner_account_id_or_name,
    approved_account_id_or_name,
    approved_operators,                     # list of operators
    token_uri,
    )
p.nft_mint("1.2.7", "1.30.11", "1.2.7", "1.2.7", "1.2.7", self.nameNft)
p.nft_safe_transfer_from(
    operator_,                # operator account name or id
    from_,
    to_,
    token_id,
    data,                     # notes as string
    )
p.nft_safe_transfer_from("1.2.7", "1.2.7", "1.2.9", "1.31.5", "whatever")
def nft_approve(
    operator_,
    approved,         # approved account id or name
    token_id,
    )
p.nft_approve("1.2.9", "1.2.8", "1.31.5")
def nft_set_approval_for_all(
    owner,
    operator_,
    approved,
    )
p.nft_set_approval_for_all("1.2.7", "1.2.10", True)
Function uint64_t database::get_random_bits(uint64_t bound)
peerplays/libraries/chain/include/graphene/chain/protocol/types.hpp
typedef fc::ripemd160 secret_hash_type;


peerplays/libraries/fc/include/fc/crypto/hash_ctr_rng.hpp
template<class HashClass, int SeedLength>

class hash_ctr_rng
{...}
peerplays/libraries/chain/include/graphene/chain/database.hpp 

fc::hash_ctr_rng<secret_hash_type, 20> _random_number_generator;
peerplays/libraries/chain/db_management.cpp

_random_number_generator(fc::ripemd160().data())
peerplays/libraries/chain/db_update.cpp

modify( _dgp, [&]( dynamic_global_property_object& dgp ){
      secret_hash_type::encoder enc;       
      fc::raw::pack( enc, dgp.random );       
      fc::raw::pack( enc, b.previous_secret );        
      dgp.random = enc.result();
      _random_number_generator = fc::hash_ctr_rng<secret_hash_type, 20>(dgp.random.data());
peerplays/libraries/chain/db_update.cpp

uint64_t database::get_random_bits( uint64_t bound )
{
   return _random_number_generator(bound);
}

peerplays/libraries/fc/include/fc/crypto/hash_ctr_rng.hpp

      uint64_t operator()( uint64_t bound )
      {
         if( bound <= 1 )
            return 0;
         uint8_t bitcount = boost::multiprecision::detail::find_msb( bound ) + 1;
         // probability of loop exiting is >= 1/2, so probability of
         // running N times is bounded above by (1/2)^N
         while( true )
         {
            uint64_t result = get_bits( bitcount );
            if( result < bound )
               return result;
         }
      }

Account History

The history API is available from the full node via websockets.

Account History

get_account_history

Get operations relevant to the specified account.

vector<operation_history_object> graphene::app::history_api::get_account_history(
    const std::string account_id_or_name, 
    operation_history_id_type stop = operation_history_id_type(), 
    unsigned limit = 100, 
    operation_history_id_type start = operation_history_id_type())const
  • account_id_or_name: The account ID or name whose history should be queried

  • stop: ID of the earliest operation to retrieve

  • limit: Maximum number of operations to retrieve (must not exceed 100)

  • start: ID of the most recent operation to retrieve

A list of operations performed by account, ordered from most recent to oldest.

get_account_history_operations

Get only asked operations relevant to the specified account.

vector<operation_history_object> graphene::app::history_api::get_account_history_operations(
    const std::string account_id_or_name, 
    int operation_type, 
    operation_history_id_type start = operation_history_id_type(), 
    operation_history_id_type stop = operation_history_id_type(), 
    unsigned limit = 100)const
  • account_id_or_name: The account ID or name whose history should be queried

  • operation_type: The type of the operation we want to get operations in the account ( 0 = transfer , 1 = limit order create, …)

  • stop: ID of the earliest operation to retrieve

  • limit: Maximum number of operations to retrieve (must not exceed 100)

  • start: ID of the most recent operation to retrieve

A list of operations performed by account, ordered from most recent to oldest.

get_relative_account_history

Get operations relevant to the specified account referenced by an event numbering specific to the account. The current number of operations for the account can be found in the account statistics (or use 0 for start).

vector<operation_history_object> graphene::app::history_api::get_relative_account_history(
    const std::string account_id_or_name, 
    uint64_t stop = 0, 
    unsigned limit = 100, 
    uint64_t start = 0)const
  • account_id_or_name: The account ID or name whose history should be queried

  • stop: Sequence number of earliest operation. 0 is default and will query ‘limit’ number of operations.

  • limit: Maximum number of operations to retrieve (must not exceed 100)

  • start: Sequence number of the most recent operation to retrieve. 0 is default, which will start querying from the most recent operation.

A list of operations performed by account, ordered from most recent to oldest.

Market History

get_fill_order_history

Get details of order executions occurred most recently in a trading pair.

vector<order_history_object> graphene::app::history_api::get_fill_order_history(
    std::string a, 
    std::string b, 
    uint32_t limit)const
  • a: Asset symbol or ID in a trading pair

  • b: The other asset symbol or ID in the trading pair

  • limit: Maximum records to return

a list of order_history objects, in most recent first order

get_market_history

Get OHLCV data of a trading pair in a time range.

vector<bucket_object> graphene::app::history_api::get_market_history(
    std::string a, 
    std::string b, 
    uint32_t bucket_seconds, 
    fc::time_point_sec start, 
    fc::time_point_sec end)const
  • a: Asset symbol or ID in a trading pair

  • b: The other asset symbol or ID in the trading pair

  • bucket_seconds: Length of each time bucket in seconds.

Note: It needs to be within result of get_market_history_buckets(), otherwise no data will be returned

  • start: The start of a time range, E.G. “2018-01-01T00:00:00”

  • end: The end of the time range

A list of OHLCV data, in least recent first order.

If there are more than 200 records in the specified time range, the first 200 records will be returned.

get_market_history_buckets

Get OHLCV time bucket lengths supported (configured) by this API server.

flat_set<uint32_t> graphene::app::history_api::get_market_history_buckets()const

A list of time bucket lengths in seconds.

For example, if the result contains a number “300” it means this API server supports OHLCV data aggregated in 5-minute buckets.

Role Based Permissions API

API Calls for Role Based Permissions (RBPs)

Operations

Create Custom Permission

p.custom_permission_create(
    permission_name,
    owner_account=None,
    weight_threshold=[],
    account_auths=[],
    key_auths=[],
    address_auths=[],
    )

For example

    p.custom_permission_create(
        testperm1,
        owner_account="1.2.7",
        weight_threshold=1,
        account_auths=[["1.2.8", 1]])

Custom Permission Update

p.custom_permission_update(
    permission_id,
    owner_account=None,
    weight_threshold=[],
    account_auths=[],
    key_auths=[],
    address_auths=[],
    )

For example

            p.custom_permission_update(
                    permission_id,
                    weight_threshold=1,
                    account_auths=[["1.2.9", 2]],
                    owner_account="1.2.7"
            )

Custom Permission Delete

p.custom_permission_delete(
    permission_id,
    owner_account=None,
    )

For example

            p.custom_permission_delete(
                    permission_id,
                    owner_account="1.2.7"
            )

Custom Account Authority Create

p.custom_account_authority_create(
    permission_id,
    operation_type,
    valid_from,
    valid_to,
    owner_account=None,
    )

For example

p.custom_account_authority_create(
                    permission_id,
                    0,
                    "2020-07-27T00:00:00",
                    "2030-07-27T00:00:00",
                    owner_account="1.2.7")

Custom Account Authority Update

p.custom_account_authority_update(
    auth_id,
    new_valid_from,
    new_valid_to,
    owner_account=None,
    )

For example

p.custom_account_authority_update(
            authority_id,
            "2020-07-27T00:00:00",
            "2040-07-27T00:00:00",
            owner_account="1.2.7")

Custom Account Authority Delete

p.custom_account_authority_delete(
    auth_id,
    owner_account=None,
    )

For example

    p.custom_account_authority_delete(
            authority_id,
            owner_account="1.2.7")

RPC Info calls

get_custom_permissions(account)
get_custom_permission_by_name(account, permission_name)
get_custom_account_authorities(account)
get_custom_account_authorities_by_permission_id(permission_id)
get_custom_account_authorities_by_permission_name(account, permission_name)
get_active_custom_account_authorities_by_operation(account, int operation_type)

RNG Technical Summary

Introduction

The Peerplays blockchain RNG was initially added to the blockchain to provide draw features for the Easy5050 decentralized application (DApp).

The first release of the RNG was localized to the Easy5050 DApp and wasn't exposing the number generated via an API, or a similar mechanism, such that other DApps or users could consume them.

For the second release of the RNG the functionality was extended to become a general RNG, with a public API, for supporting games such as Slots, Poker, Roulette, Raffle, Bingo, Keno, etc.

How the Random Numbers are Generated

Random numbers are generated from secret hashes taken from the previous and current block, which are then combined into a single data stream and encoded using the ripemd160 algorithm, and finally fed into a random number generator as a seed.

For more information on the ripemd160 algorithm see:

https://en.wikipedia.org/wiki/RIPEMD

Block-Hash Randomness

In this approach, the hash of blocks or transactions is used as the source of randomness. As the hash is deterministic, everyone will get the same result. A block, once added to the blockchain, is likely to stay there forever, therefore everyone can verify the correctness of the generated numbers.

Consider an example of a lottery service that adopts this method. The players first buy a ticket by placing their number before a specific time, say 7PM everyday. After 8PM, the buying ticket phase is closed, the protocol proceeds to the next phase which is to determine the winning numbers for a ticket. This ticket is calculated based on the hash of the first block accessible for everyone on the blockchain after 8PM.

As we can see, at 7PM, no one can predict the hash of block at 8PM which makes the service seemingly a sound one. However, this hash is subject to manipulation by the block-signers of the blockchain. When the reward of the lottery is small, the block-signers have little motivation to tamper with the block, but as soon as this amount is larger than the block reward plus the transaction fees, there is a chance that witnesses will start influencing the block-hash to generate their desired numbers.

So on it's own a block-hash level of randomness is not enough. This is why the Peerplays RNG extends the block-hash mechanism by using the hash as a seed for randomization along with the repemd160 algorithm and Secure Hash Algorithm (SHA).

Distributed Ledger Technology (DLT)

Peerplays, and other blockchains, are one type of a distributed ledger. Distributed ledgers use independent computers (referred to as nodes) to record, share and synchronize transactions in their respective electronic ledgers (instead of keeping data centralized as in a traditional ledger).

The immutability of DLT is critical for the RNG because it ensures that once a random number is generated it is authentic and can't be changed.

Witness Randomness

Peerplays is based on the Delegated Proof of Stake (DPOS) consensus mechanism, which means that the block signers (Witnesses) are all elected by the token holders. This is important from an RNG perspective because it requires loyalty, commitment and honesty to get voted in as a Witness. Since a component of the randomness is based on the block hash, knowing that the block signers are a trusted, elected, group greatly mitigates the risk of block tampering.

Peerplays further extends the block-signing robustness and randomness because:

  1. Not all Witnesses are block-signing (active) Witnesses. There is a second level of consensus that has to happen before a Witness is promoted to an active Witness.

  2. Not all active Witnesses are signing blocks at any given time. The blockchain randomly selects which Witnesses are signing at ten minute intervals.

Because of the role of the Witnesses, Peerplays has two levels of randomness. First the Witnesses themselves are randomly selected, and secondly the randomness of the number generation itself.

Testing

For testing the RNG, the “Dieharder” random number generator testing suite was used.

Dieharder is intended to test generators, not files of possibly random numbers as the latter is based on the mistaken view of what it means to be random. Perfect random number generators produce "unlikely" sequences of random numbers -- at exactly the right average rate. Testing an RNG is therefore quite subtle.

Dieharder is a tool designed to push a weak generator to unambiguous failure.

For more information on Dieharder see:

https://webhome.phy.duke.edu/~rgb/General/dieharder.php

Install prerequisites for running RNG tests

sudo apt install dieharder

To run RNG test suite, use the following command:

$ ./tests/random_test

Gaming Laboratories International (GLI)

GLI are an internationally recognized institute offering the the most experienced and robust RNG testing methodologies in the world. This includes software-based (pseudo-algorithmic) RNG’s, hardware RNG’s, and hybrid combinations of both.

The Peerplays RNG has been submitted to GLI for approval [TBD: or has 'been approved']

GLI generally performs the testing of applications and games, such as Keno, as opposed to an API. The game testing will automatically include the backend API as well. On successful completion of all tests each application will be certified by GLI.

For each new game, different testing will be required. An example would be the Easy5050 DApp that can be tested and with all subsequent releases, tested again.

However, as the core Peerplays RNG is a blockchain (back-end) implementation and not an application it can only be approved by GLI rather than certified.

API

The RNG has a very simple API for generating random numbers, requiring just a single API call to get_random_bits(bound) ; supplying an upper bound.

get_random_bits(uint64_t bound)

For more information on the API see the RNG API.

NFTs for Staking Creator Tokens

How communities can get work done. An example dapp idea using Peerplays.

1. The Concept

Peerplays communities come in all shapes and sizes. Sometimes a community will need some specialized work to be done to accomplish the vision of the community. The Peerplays network covers some basic functions for everyone like, sidechain transfers, random number generation, asset exchanges, etc. But what if a community needs something else?

One example would be a community for book publishing. This community needs several specialized workers: file encoding, file storage, content verifiers, and Content Delivery Network (CDN) gateways to name a few. None of these are covered by Peerplays directly. But we can create a system which will incentivize community members to complete this work in a decentralized way.

2. The Plan

2.1. Components

This concept will make use of some Peerplays components:

  • Service Infrastructure Pools

  • NFTs

  • Custom Permissions

  • User Issued Assets

This concept will also need some development for its custom components. These would be created by you, the dapp developer:

  • Worker Node Software

  • Decentralized User Interface

2.2. Putting it together

As the creator of the Peerplays community, you can use the components available to you to build a new system. The system can be simple or complex to best fit the needs of the community.

In this example system:

  1. Community members enjoy the books available within and written by the community. The members purchase a specific community token (LIBRARY, for example) directly from the community. The profit from these sales is fed to the Service Infrastructure Pool.

  2. The members then stake the LIBRARY tokens to receive community NFTs. The NFTs allow community governance voting and generate another community token (BOOK, for example) as rewards to the members over time.

  3. Now a content creator (an author) needs the services of a community worker node. The author needs to pay the worker with BOOK token. So the author buys BOOK from the exchange and uses it to publish a book via the worker nodes.

  4. BOOK is in high demand because it's also used by the members to check-out books for a limited time. So the workers can sell the BOOK in the exchange for profit.

The system so far is of a medium complexity and could satisfy the needs of the community. It's possible to add a little more to introduce some competition and buy-in among the worker nodes while also making the BOOK token deflationary.

  • The workers can stake the BOOK token to receive a special worker NFT. This NFT provides the worker with "work power" which diminishes over time. The work power determines the amount of BOOK a worker is paid for performing a job as well as their priority for receiving jobs.

The Peerplays network makes many things possible. With imagination and will-power, you can create systems like this to realize your vision.

3. Related Documents

The components listed in this guide will cost transaction fees. To calculate how much PPY you'll need to make these transactions and meet your development goals, please see the Calculating Costs guide.

comparison-between-scenarios-for-handling-deposits-and-withdrawals

Comparison between scenarios for handling deposits and withdrawals

Intro

The purpose of deposit handling is to detect cryptocurrency payment from Peerplays user (currently only Bitcoin), and issue matching amount of Peerplays assets (pBTC) on Peerplays network, which user can use in games.

The purpose of withdrawal handling is to do the same thing in reverse - user will initiate withdrawal process, system will exchange his Perplays assets (pBTC) for the matching amount of cryptocurrency, and send this amount to user’s account.

In this document, I will describe scenarios we are considering, and present the main differences between them. There are features common to all scenarios (like user address mappings and sidechain manager features, verifying transaction validity reported by different SONs...), and I will consider them to be out of the scope of this document.

Scenarios

At this moment we are considering three possible approaches:

  • S1: Multisignature primary wallet controlled by SON network, holding all the funds. All transfers are made to and from this multisignature wallet.

  • S2: Proxy account, created by Peerplays network, paired with multisignature primary wallet controlled by SON network. On deposit, user sends funds to proxy account and funds are moved from proxy account to a primary wallet. On withdrawal, user initiates withdrawal process and funds are moved from primary wallet to proxy account or to another account belonging to the user. There is no clear suggestion on the approach. This is existing sidechain design, implemented in feature_sidechain branch.

  • S3: 3 of 3 multisig wallet, controlled by blockchain network, SON network and user, paired with temporary primary wallet controlled by SON network. On deposit, user sends funds to 3 of 3 wallet, funds are staying in 3 of 3 wallet, wallets are periodically rebalanced to match the balance between 3 of 3 wallet and Peerplays pBTC, and funds are moving between 3 of 3 accounts and temporary primary wallet. On withdrawal, user initiates withdrawal process, selects one of three withdrawal scenarios, and once the withdrawal is executed, funds will be moved from temporary primary wallet to 3 of 3 wallet or to another account belonging to the user. There is no clear suggestion on the approach. This is Jonathans proposal.

General description of deposit process

  • User send’s cryptocurrency to some address controlled by Peerplays. Depending on what's behind this address, we will need more or less work for implementation and maintaining it during system usage. Current suggestions are:

    • S1: User sends funds to a primary wallet, holding all the funds, and controlled by SON network.

    • S2: User sends funds to a user’s single signature proxy account, created by Peerplays network. Network will pull the funds from proxy account to primary wallet controlled by SON network, when applicable.

    • S3: User sends funds to a 3 of 3 wallet, where signers are Blockchain network, SON network and user.

  • SON network monitors this address for transfers, and when transfer is detected, it will initiate a process of issuing pBTC.

    • S1: SON network monitors address of primary wallet. When transfer is detected, the system will identify user who made the payment and issue pBTC to user’s Peerplays address.

    • S2: SON network monitors address of users’s single signature proxy account. When transfer is detected, funds will be moved from proxy account to primary wallet, system will identify user who made the payment, and issue pBTC to user’s Peerplays address.

    • S3: SON network monitors address of 3 of 3 wallet. When transfer is detected, funds will stay locked in 3 of 3 wallet, system will identify user who made the payment, and issue pBTC to user’s Peerplays address.

  • Once the pBTC is issued, user will not be able to freely handle the crypto-currency he initially paid. Current suggestions are:

    • S1: Funds are moved to Primary wallet controlled by network.

    • S2: Funds are moved from proxy account to Primary wallet account

    • S3: Funds stay in a 3 of 3 wallet, and in order to move them, three signatures are required

General description of withdrawal process

  • User initiate withdrawal process. Depending on how the user will initiate withdrawal process we we will need more or less work for implementation and maintaining it during system usage. Current suggestions are:

    • S1: No clear suggestion on this. However, it can be started by initiating transfer from user’s peerplays account to a primary wallet controlled by SON network in Peerplays network.

    • S2: No clear suggestion on this. However, it can be started by initiating transfer from user’s peerplays account to a primary wallet controlled by SON network in Peerplays network.

    • S3: User can select one of three withdrawal methods, instant, standard and econo. The difference between these three is the price the user will pay for withdrawal, and the amount of time needed for withdrawal to be processed. If user pays higher price, withdrawal will be processed faster.

  • When SON network receive withdrawal process request, it needs to identify user who initiated a request, and send funds to his account. In current scenario, we only handle BTC. In the future, when we support more blockchain networks, we also need to identify the network where we will send crypto-currency (e.g. if user made his paymetn from BTC and ETH network, we can allow him to choose whether he will be paid in BTC or ETH). However, we will also need a way to prevent user to use Peerplays network as an exchange office, in order to speculate with exchange rates, and pull more funds from the system, without actually using the Peerplays network for gaming.

    • S1: No clear suggestion on this, but we can send funds to a user account on target sidechain registered in the system.

    • S2: No clear suggestion on this, but we can send funds to a user account on target sidechain registered in the system, or to a user’s proxy account used for initial payment.

    • S3: Funds will be sent to 3 of 3 wallet during rebalance. However, user still needs 3 signatures to withdraw his funds from 3 of 3 to his personal account. There is no clear suggestion on how this will be done.

Problems on active SONs set change

Various problems may occur when we are using multi signature wallets controlled by SONs network, and active SONs set changes. Multisignature wallet is not updateable - we can’t update the list of signatures required for using funds from multisignature wallet. When active SONs set changes, multisignature wallets created by previous active SONs set may become unusable (because previous SONs holding ⅔ weight are not available anymore), rendering funds unavailable. To prevent this, the general approach is to recreate the multi signature wallets, and move all the funds from the old one to the new one. For some blockchain, like Ethereum, this problem may be easily solved by using smart contracts, and no recreation will be needed. However, since our current target is Bitcoin, the app

  • S1: Primary wallet needs to be recreated and funds moved from old wallet to the new one.

  • S2: Primary wallet needs to be recreated and funds moved from old wallet to the new one.

  • S3: All 3 of 3 wallets, and temporary primary wallet needs to be recreated and funds moved from old wallets to the new ones. User interaction with the system might be needed for some of these actions.

Rebalancing

  • S1: Rebalancing is not needed.

  • S2: Rebalancing is not needed.

  • S3: All 3 of 3 are periodically rebalanced to match the balance of pBTC in Peerplays network. Rebalance can be optimized by addressing only accounts that actually needs rebalancing, and transferring only differences that are needed to match the BTC and pBTC balances.

Comparison

  • S1: This design is a kind of “lowest common denominator” approach, that will offer functional system, with lowest costs (single transaction for deposit, and single transaction for withdrawal), it is easiest to implement and most flexible to add changes later. It is easier to convert S1 into S2 or S3 than S2 into S3 or S3 into S2, or any other way around. The main problem with this design is PW recreation and moving funds from old to the new one, and the fact that PW will hold all Bitcoins in the network, which can make him target for hackers in the future, when it may hold enough value for somebody to go for it.

  • S2 is very similar to S1 in all terms, but it is not clear why do we need the proxy account. It increases cost (one transaction for user account to proxy and one transaction for proxy to PW for deposit, and one transaction for PW to proxy and one transaction for proxy to user account for withdrawal). The main problem with this design is PW recreation and moving funds from old to the new one, and the fact that PW will hold all Bitcoins in the network, which can make him target for hackers in the future, when it may hold enough value for somebody to go for it. Another problem is increased costs of system usage, because of using proxy accounts.

  • S3: By far the most complex design, advertised as “no primary wallet needed”, but from the discussion we had, we actually do need it for rebalancing and for holding the surplus of assets that are not distributed to 3 of 3 wallets during rebalancing. Temporary or not, multisig wallet controlled by SON network is there, and it needs handling. User interactions with the system in order to allow pulling funds from 3 of 3 wallet to temporary primary wallet (for handling "half signed" PUAT and PUST transactions) is problematic from the point of getting funds earned by Peerplays network, as user does not have clear motivation to sign any of these (e.g. user’s pBTCs are all spent, so why would user care did Peerplays pulled the BTC from his account or not). The good side of this design is that PW will not hold all assets, only part of them, while the other part will be distributed in user’s 3 of 3 wallets.

Recommendation

In order to unblock development, I recommend that we go with S1, since it will enable us to get the functionality we need with the least effort and shortest time. With S1 as a starting point, we will implement all common features for all three designs (son communication, multisig wallet recreation, moving funds, signing transactions, user address mappings, sidechain manager functionalities, etc…) and once we have S1 done, we can tweak it to any other scenario.

son-rewards-lld

1. Purpose

The purpose of this document is to provide low-level design for making payments to SONs for their contribution to the Peerplays network.

2. Scope

The design requirement listed in this document will be limited to the payments to SON Nodes.

The document will also outline the way we pay witnesses currently in our network.

The document will also outline the new chain parameters required to configure the payments to SONs dynamically.

The document will also outline the new data structures required to identify the transactions that a SON participated in.

All the terminology used in the document is generic and will not be specific to any particular cryptocurrency like BTC or ETH.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Types of transactions

4.1 Transfer cryptocurrency(i.e. like BTC, ETH) from Deposit Address to PW Address

In this case, SONs have to sign the transaction to be successful.

So a reward should be made to SONs in this case.

Miner fee for the external chain is also required but it is out of the scope of this document.

4.2 Transfer cryptocurrency from Old PW Address to New PW Address

In this case, SONs have to sign the transaction to be successful.

So a reward should be made to SONs in this case.

Miner fee for the external chain is also required but it is out of the scope of this document.

4.3 Transfer UIA (User Issued Asset Eg. pBTC) from one account to another

In this case, there is no need for a SON to sign for the transaction to be successful.

This is a normal on-chain transaction. This has been supported in all the graphene-based chains for long.

So no reward is required in this case. But a witness fee is applicable as in the case of core asset transfer.

5. How it all works currently

5.1 How are witnesses paid

Currently whenever a new block is generated by a particular witness, we immediately deposit the amount into the vesting balance of the witness account.

The amount comes from the witness_budget allocated globally during the previous maintenance interval.

This is stored in dynamic_global_property_object of the blockchain for faster access.

5.2 How fee is collected

For every operation, there is a rate specified that goes as the fee to the network.

For core asset transaction, the fee is directly deducted from payer's account.

For the UIA asset transaction, the fee is converted to the core using the base exchange rate of the UIA.

Between two maintenance intervals, the core fee is accumulated in the core asset's asset_dynamic_data_object.

5.3 How is budget calculated currently

At the end of each maintenance, we calculate the budget for the coming cycle.

Some of the parameters we take into consideration are witness_budget, worker_budget, core_accumulated_fee, leftover_witness_budget etc.

A simple equation to arrive at the final budget (current_supply) is,

current_supply = current_supply + (required_witness_budget + required_worker_budget - leftover_worker_funds - core_accumulated_fee - leftover_witness_budget)

reserve_supply = max_supply - current_supply

At the end of every maintenance, the above parameters are updated in the databases.

6. Proposed Design Change for SONs

One of the requirements for the SONs is to pay the SON accounts proportional to the number of transactions they participate in.

So there is a need to know the number of transactions a particular SON object has participated in from the last payout period till now.

There is also a requirement to pay SONS_DAILY_MAX_REWARD to set of SONs operating in the network.

And this should be configurable so that in future if we have to add more SONs to handle transactions from other cryptocurrencies, we need more daily rewards or vice-versa.

As can be seen in the previous section as to how the budget is calculated, how the core amount is pooled in from the reserve, we can follow a similar approach for SONs as well.

With SONs budget factored into the budget calculations, our new equation would be,

current_supply = current_supply + (required_witness_budget + required_worker_budget + required_son_budget - leftover_worker_funds - core_accumulated_fee - leftover_witness_budget - leftover_son_budget)

reserve_supply = max_supply - current_supply

required_witness_budget ==> required witness budget till next maintenance interval

required_worker_budget ==> required worker budget till next maintenance interval

required_son_budget ==> reserved SON budget to be paid out in the next maintenance interval = (chain_parameters.son_pay_max)

leftover_worker_funds ==> Remaining funds from previous worker payout

core_accumulated_fee ==> Accumulated fee (after all the cuts removed from it), since the last maintenance interval.

leftover_witness_budget ==> Leftover funds from previous witness budget ( happens if any block is missed in between )

leftover_son_budget ==> Leftover funds from previous son budget ( happens if there are no SON transactions on the network )

For us to efficiently find the number of transactions a SON has signed, we need a new implementation_id object that complements our proposed son_object.

We store the transaction linked list that the SON has participated in and the number of transactions since the last payout.

This way during maintenance we can calculate payouts faster for each SON.

A new chain parameter to change the max daily rewards is also required.

6.1 parameter_extension.son_pay_daily_max

This parameter is used to specify the current son max payout.

It can be re-configured by committee_member_update_global_parameters_operation.

6.2 dynamic_global_property_object.son_budget

This parameter is used to denote the son_budget till next payout interval.

This is set every payout interval.

6.3 son_statistics_object

This new class is an implementation type object.

It stores the data which is changed frequently and better to separate it from the SON object.

It has data about the transactions and number of pending since last payout.

6.4 pay_sons

This function should be introduced and called from perform_chain_maintenance.

After this new budget should be recorded and saved.

claiming initial son vesting lld

1. Purpose

The purpose of this document is to provide low-level design for the process of claiming the initial vesting amount to become SON on PPY Blockchain.

2. Scope

The design requirement listed in this document will be limited to the de-registration of SON Node from active SONs and claiming the initial vesting amount by a user.

The document will also outline the function flow for how de-registration of SON node happens.

The document will also outline the new chain parameters required to configure the initial vesting amount and vesting period duration after de-registration happens.

The document will also outline the new data structures required to control the user from claiming the initial vesting amount before the vesting period duration expires.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Current Vesting scenario for GPOS

As proposed and implemented in GPOS, user can vest a certain amount to,

  1. Participate in voting for proposals.

  2. To earn a part of commissions for transactions.

The vesting period is currently 6 months and it is divided into sub-periods of 1 month.

At the end of every sub-period, a parameter called Vesting Factor (typically between 0 to 1) is calculated based on user participation.

The Vesting Factor decreases if a user doesn't participate in any voting activity for the preceding sub-period.

Users can retain their starting Vesting Factor of 1 if they continue to participate in voting in every sub-period.

And commissions are paid out proportional to the Vesting factor.

Any commission which is not paid to users because of their inactivity is transferred into a separate account which can be used further.

5. Vesting Requirement for SON

As proposed in the Functional specification of SON, a user who wants to become an SON should vest a certain amount (50 PPY) in a separate account.

The vested amount would be locked indefinitely until 2 days after the SON is deregistered on the network.

The vesting amount doesn't change and rewards are paid into liquid/normal account of the user.

6. Perceived Challenges for implementing Vesting for SON

As seen above for GPOS, at the time of the creation of Vesting Account a vesting period of at least one sub-period can be set to prevent users from withdrawing the vesting amount.

So when a user tries to withdraw his vesting amount, a vesting policy which was initialized during the creation of the vesting account can be used to decline the withdrawal.

However in SON Vesting at the time of creation, we can't initialize a policy with a particular duration that can decline user withdrawals.

A policy cannot be initialized at the time of Vesting account creation because the vesting period depends on the time of deregistration of SON.

7. Current list of Vesting policies

Currently, there are two types of vesting policies are in place,

7.1 linear_vesting_policy

This vesting policy is used to mimic traditional stock vesting contracts where each day a certain amount vests until it is fully matured.

No amount can be withdrawn before a certain number of cliff seconds have elapsed.

7.2 cdd_vesting_policy

This policy defines vesting in terms of coin-days accrued which allows for dynamic deposit/withdraw.

The economic effect of this vesting policy is to require a certain amount of interest to accrue before the full balance may be withdrawn.

Interest accrues as coin days = (balance * length_held). If some of the balance is withdrawn, the remaining balance must be held longer.

8. Proposed ways of de-registering SON

An SON can be deregistered in two ways according to the functional requirements,

  1. remove_son called for SON in any state by the user from the wallet.

  2. If an active SON is in maintenance for more than 12 hours.

9. Design changes suggested

9.1 son_vesting_amount

This is the minimum amount that should be vested in order to become an SON.

Currently, this is proposed to be 50 PPY.

This parameter can be changed through committee_member_update_global_parameters_operation.

9.2 son_vesting_period

This is the minimum vesting duration a user has to wait from the time an SON is considered to be deregistered.

Currently, this is proposed to be 2 days ( 2 * 86400 seconds).

This parameter can be changed through committee_member_update_global_parameters_operation.

9.3 vesting_balance_type

A new vesting_balance_type son is introduced like the one similar to gpos.

This helps in identifying the type of vesting amount.

9.4 dormant_vesting_policy<linear_vesting_policy>

This new policy just acts a wrapper around the existing policies.

As mentioned above the challenge in implementing the son vesting is that exact vesting duration is not known at the time of the creation of vesting_balance_object.

Till the point, an SON is considered as deregistered this policy would be in dormant mode and declines any vesting withdrawals initiated by the user.

Once an SON is marked as deregistered, the policy comes out of dormant mode and vesting duration is set to 2 days from deregistration.

From then on policy would just act as linear_vesting_policy.

9.5 update_active_sons

This function is introduced into the database class to handle the task of picking top N SONs at maintenance interval.

This also performs the task of deregistering the SON and activating the new dormant policy residing inside son_object.

9.6 son_status

This enum holds the state of an SON.

active - An SON user account selected among the top N SONs. ( N = 15 proposed currently ).

inactive - An SON who is idle and not actively performing the duties of maintaining the sidechain operations of another smart coin.

maintenance - An SON has gone down for maintenance but not deregistered yet.

9.7 create_vesting_balance

Argument is_gpos needs to be changed to either a string or an enum to cater to the new requirements of son vesting balance type.

10. UML and Sequence Diagrams

11. Scenarios to consider

11.1 SON gone down into maintenance mode and user issues remove_son

remove_son takes precedence and the node is deregistered at the next maintenance interval.

The new dormant vesting policy is activated.

11.2 remove_son followed by create_vesting_balance/create_son within the 2-day vesting period

TODO: This should be specified in the FR Document.

11.3 SON gone down into maintenance mode, then de-registered after 12 hours period and user issues remove_son

The first timestamp when the SON initially de-registered takes precedence.

# List of variables

## Auth for a PostgreSQL database
DB_DATABASE
DB_HOST
DB_PASSWORD
DB_PORT
DB_USER

## Third party login
DISCORD_ID
DISCORD_SECRET
FACEBOOK_ID
FACEBOOK_SECRET
GOOGLE_ID
GOOGLE_SECRET

## Routes
FRONTEND_CALLBACK_URL # https://example.com/callback
FRONTEND_URL # https://example.com
BACKEND_URL # https://example.com/api

## Mailer settings
MAILER_HOST
MAILER_PASS
MAILER_PORT
MAILER_SENDER
MAILER_USER

## Peerplays Settings

PEERPLAYS_FAUCET_URL
PEERPLAYS_PAYMENT_ACCOUNT_ID
PEERPLAYS_PAYMENT_ACCOUNT_WIF
PEERPLAYS_REFERRER
PEERPLAYS_WS # node api endpoint
PEERPLAYS_ASSET_ID

## NodeJS
MODULE # API
SESSION_SECRET # randoms string
# List of variables

BACKEND_NAME # peerid-backend
BACKEND_PORT # 3000
FRONTEND_NAME # peerid-gui
VHOST # DNS/localhost
Storing Secrets in Amazon Parameter Store to use in ECS

Brain Storming

Brain Stroming

Identity Provider - Brainstroming

Created by [Bobinson Bobby]

Facilitator

@Bobinson Bobby

Participants

@Prabhjot Singh @Satyanarayana Koneru

Brainstorm date

Jun 11, 2020

Video conference link

On this page

Brainstorm planning

Goals of the brainstorm

Finalize the requirements for the Identify provider

Participant instructions

Compare existing Identity / SSO providers

Brainstorm pre-work & ideas

SSO document prepared by @Prabhjot Singh in 2019

HiveSigner

Scatter

Study Reference Architectures for dApps

Problem Statement

One of the challenges everyone in the blockchain is agreeing and facing is the lack of standards for signin, interaction with between wallets, an SSO mechanism similar to OpenID (Janrain version) which later got extended to Oauth. Needless to say, the blockchain space doesn't even have something similar to a simple gravtar system.

In the context of SSO few items we are trying to do is:

  1. For a user with Twitch/Facebook account, it should be easy to sign up for a Peerplays account

  2. Once a user owns say, EOS or Bitcoins, she should be able to easily signup or use Peerplays without going through the entire cycle of account creation etc.,

  3. Our target market uses additional apps like STEAM, Discord & YouTube gaming (& there could be betting related apps).

The objective of the SSO is to provide a simpler mass onboarding mechanism for people with or without blockchain accounts to start participating in various public blockchains. Such an SSO service like Bitpass can have a massive impact on the blockchains. Graphene-based chains (Bitshares, SCORUM, STEEM & EOS), Bitcoin & Ethereum should be considered as our target blockchains. While storing private keys and "Brain Keys" should not be allowed, we can store Tokens like JWT with an expiry against private keys and store them in a secure database. The database will be encrypted at the store and in transit using TLS to ensure safety. In a nutshell, we can store a mapping between a private key-derived Time & URL-bound unique tokens & various services.

Further use cases: KYC similar to Passport from Telegram, create discord bots, Telegram bots, Access Twitch widgets

The wallet

Similar to the chains and services there is also a challenge with numerous wallet implementations and no clear, unified mechanism for the dApps to interact with wallets. In the case of lesser known blockchain projects its important to get noticed by Software Wallets like Exodus and hardware wallets like Ledger. We would essentially expose a mechanism for the wallets and dApps to integrate with us and also act as signature providers.

The transit API is such an example.

https://medium.com/eos-new-york/the-transit-api-connecting-dapps-signature-providers-5d816c056f7f

Along with the wallet, if we can also consider an extension of Transit API for Peerplays, that will be a great achievement.

The combination of SSO and wallet implementation with a Transit API-like interface will help us to onboard "masses" & safely interact with Peerplays via various dApps.

Thoughts and ideas are welcome!

Brainstorm outcomes

  1. In a large dApp like peaked.com or StreamersEdge.com an identity provider that can help end users sign transactions is helpful to isolate the authentication and authorization functionalities from the application business logic

  2. We will have to provide easy account creation using existing social accounts like Facebook, Twitter, etc., as opposed to be expecting users to be blockchain savvy. This would mean that the identity provider component should store the MASTER_PASSWORD or the generated keys and lease them to the dApps as when needed.

Software Requirements

1. Introduction

The rationale behind the dApps is to develop applications using rock-solid transaction capabilities, tamper-proof immutability, and the impenetrable security offered by the Peerplays blockchain platform.

While these are compelling reasons for developers to use blockchain technology, the need for end-to-end application development knowledge, traditional enterprise-backed software development methods, etc creates entry barriers for developers.

A Blockchain Middleware System (BMS) platform with various components will be built by PBSA to address these unique challenges. Our goal is to expose general-purpose APIs which can be accessed in a language and platform-agnostic way thus making it possible for developers of varying skill sets to create applications on the blockchain.

(Figure 1: High-level design topology of a dApp)

2. Identity management

User management and identity management are a major part of any application development and the blockchain with unique security constraints brings challenges to the same. While the public key cryptography-based account access provided by the Peerplays blockchain is secure compared to a username password based authentication, the same makes it challenging and next to impossible for laymen to create and use dApps. A common alternative proposed is using cryptocurrency wallets. This doesn't solve the onboarding challenge as a tiny set of internet browsing population and cryptocurrency wallets.

To ensure faster and smoother onboarding of users, Peerplays is thus creating an identity management and SSO platform that helps anyone with an email address, Facebook, or Google account to easily create an account on the Peerplays blockchain. For tech-savvy users, the traditional blockchain mechanism will be used to create the accounts.

In addition to the account creation, Peerplays will also provide simpler mechanisms for dApp developers to create and provision dApps and configure various dApp-level permissions.

3. Requirements

3.1 High-level Requirements

This section will define each of the high-level components of the the identify manager product - PeerID.

The components:

  • account creation

  • retrieving Peerplays keys

  • dApp provisioning

  • dApp Permissions

  • unlinking third-party services

  • Multi-Factor Authentication

  • Anti Phishing features

3.1.1 Account creation

A dApp user account creation will always involve creation of an account on the Peerplays blockchain. PeerID will provide 2 modes of account creation. The first mode will be for advanced users which will use the core Peerplays Faucet to generate a blockchain account and keys. A simpler mechanism wherein the account can be created by signing up with Facebook, and Google accounts. The list of third-party services will be increased in the future and they might include Twitter, Discord, Steam, Snapchat, etc.,

3.1.2 Retrieving Peerplays keys

Scenarios might arise that may lead a user to request the Peerplays private keys or master password. In such a scenario, requested keys or a MASTER Password will be sent to the user via an email and shown on the screen/UI. This will be an irreversible action and all the third-party links established during this process will get securely deleted from the PeerID databases.

3.1.3 dApp Provisioning

Developers must be given a simpler interface wherein they can create the dApp, assign permissions, and configure any third-party call-back URLs. Ideally, provisioning of the dApp related permissions, minting the tokens, etc., should be done using the cli_wallet. The provisioning should be used primarily for the staging and development process and the related cli commands can be used to mint tokens, assign permissions, etc., Additionally, multiple accounts can be used to create each type of provisioning. For minting any related token a high-security account can be used, permissions can be created with another user, etc., This must be detailed in the functional specifications.

3.1.4 dApp Permissions

The blockchain-level permissions capabilities should be used to create permissions.

The permissions must map users to dApps, assets, and operations based on various conditions. The conditions themself can be generic and configurable via the PeerID U

3.1.4.1 External conditions

The blockchain will expose a generic interface to validate / verify with any external validator. The dApp can perform the calls with external services like a KYC verification application to receive a callback and then set relevant attributes to a given user.

Limiting users based on conditions set in blockchain-based on external validators. (services like KYC, and geo-location). The external conditions can be is_member_of_facebook, is_MFA_enabled, etc.,

3.1.5 Miscellaneous Features

These features will be low-priority, phase II features that will ensure additional controls and enhanced security.

  • unlinking third-party services

  • Multi-Factor Authentication

  • Anti Phishing features

3.2 Functional Requirements

Account creation

  • A user should be able to create an account only by having an email, Facebook ID, or Google ID

  • A user should be able to change the passwords

  • A user should be able to import or export his Peerplays keys

  • A forgot password option must be provided

1.5.dApp provisioning

  1. The first step of the dApp creation is to create a corresponding blockchain account for the dapp. A simple UI will be provided for the same.

Aspects provisioned

  • account name

  • access credentials - usernames, passwords, permissions

  • secure tokens

  • federated logins with Google, Twitch, Youtube, Facebook, STEAM, EPIC games etc

  • support for Multi-factor authentication

Crypto API

The crypto API is available from the full node via websockets.

Blinding and Un-Blinding

blind

Get signed blocks.

Generates a Pedersen Commitment: *commit = blind * G + value * G2. The commitment is 33 bytes, the blinding factor is 32 bytes.

Tip: For more information about Pedersen Commitment see:

  • blind: Sha-256 blind factor type

  • value: Positive 64-bit integer value

A 33-byte Pedersen Commitment: commit = blind G + value * G2

blind_sum

Get SHA-256 blind factor type.

  • blinds_in: List of SHA-256 blind factor types

  • non_neg: 32-bit integer value

A blind factor type.

Range Proofs

range_get_info

Gets “range proof” information.

The cli_wallet includes functionality for sending blind transfers in which the values of the input and output amounts are “blinded.”

Note: In the case where a transaction produces two or more outputs, (e.g. an amount to the intended recipient plus “charge” back to the sender), a “range proof” must be supplied to prove that none of the outputs commit to a negative value.

proof: List of proof’s characters

A range proof info structure with exponent, mantissa, min and max values.

range_proof_sign

Proves with respect to min_value the range for Pedersen Commitment which has the provided blinding factor and value.

  • min_value: Positive 64-bit integer value

  • commit: 33-byte pedersen commitment

  • commit_blind: Sha-256 blind factor type for the correct digits

  • nonce: Sha-256 blind factor type for our non-forged signatures

  • base10_exp: Exponents base 10 in range [-1 ; 18] inclusively

  • min_bits: 8-bit positive integer, must be in range [0 ; 64] inclusively

  • actual_value: 64-bit positive integer, must be greater or equal min_value

A list of characters as proof in proof.

Verification

verify_sum

Verifies that commits + neg_commits + excess == 0.

  • commits_in: List of 33-byte Pedersen Commitments

  • neg_commits_in: List of 33-byte Pedersen Commitments

  • excess: Sum of two list of 33-byte Pedersen Commitments where sums the first set and subtracts the second

(Boolean) True in event of commits + neg_commits + excess == 0, otherwise false

verify_range

Verifies range proof for 33-byte Pedersen Commitment.

  • commit: 33-byte pedersen commitment

  • proof: List of characters

A structure with success, min and max values

verify_range_proof_rewind

Verifies range proof rewind for 33-byte Pedersen Commitment.

  • nonce: Sha-256 blind refactor type

  • commit: 33-byte pedersen commitment

  • proof: List of characters

A structure with success, min, max, value_out, blind_out and message_out values.

Requirements Specification

1. Introduction

The goal of every Peerplays dApp developer is to develop applications using the rock solid transaction capabilities, tamper proof immutability, and impenetrable security offered by the Peerplays blockchain platform.

While these are compelling reasons for developers to use blockchain technology, the need for end-to-end application development knowledge along with traditional enterprise backed software development methods create entry barriers for developers.

A Blockchain Middleware System (BMS) platform with various components will be built by the PBSA to address these unique challenges. Our goal is to expose general purpose APIs which can be accessed in a language and platform agnostic way and thus make it possible for developers of varying skill sets to create applications on the blockchain.

2. Identity Management

User and identity management is a major part in any application development. Blockchains bring challenges with their unique security constraints. The public key cryptography based account access provided by the Peerplays blockchain is secure compared to a username and password based authentication. But this method makes it challenging or even next to impossible for laymen to create and use dApps. A common alternative proposed is using cryptocurrency wallets. This doesn't really solve the on-boarding challenge as a tiny set of the internet browsing population use cryptocurrency wallets.

To ensure faster and smoother on-boarding of users, Peerplays is thus creating an identity and access management (IdAM) and SSO platform which helps anyone with an email address, Facebook, or Google account to easily create an account on the Peerplays blockchain. For tech-savvy users the traditional blockchain mechanism will be used to create the accounts.

In addition to the account creation, Peerplays will also provide simpler mechanisms for dApp developers to create and provision dApps and configure various dApp level permissions.

3. Requirements

3.1. High level Requirements

This section will define each of the high level components of the identity management product - PeerID.

The components:

  • account creation

  • retrieving Peerplays keys

  • dApp provisioning

  • dApp Permissions

  • unlinking third party services

  • Multi-Factor Authentication (MFA)

  • Anti-Phishing features

3.1.1. Account creation

User account creation within a dApp will always involve creation of an account on the Peerplays blockchain. PeerID will provide two modes of account creation. The first mode will be for advanced users which will use the core Peerplays Faucet to generate a blockchain account and keys. The second will be a simpler mechanism wherein the account can be created by signing up with an email, Facebook, or Google account. The list of third party services will be increased in the future which might include Twitter, Discord, Steam, Snapchat, etc.

3.1.2. Retrieving Peerplays keys

Scenarios might arise which may lead a user to request their Peerplays private keys or master password. In such a scenario, requested keys or a master password will be sent to the user via an email and shown on the screen/UI. This will be an irreversible action and all the third party links established during this process will be securely deleted from the PeerID databases.

3.1.3. dApp provisioning

Developers must be given a simple interface wherein they can create the dApp, assign permissions, and configure any third party call back URLs. Provisioning of the dApp related permissions, minting tokens, etc., should be done using the cli_wallet. The provisioning features within PeerID should be used primarily for the staging and development process. Additionally, multiple accounts can be used to create each type of provisioning. For minting tokens a high security account can be used. Then permissions can be created with another account, and so on. This must be detailed in the functional specifications.

3.1.4. dApp permissions

The blockchain level permissions capabilities should be used to create permissions. The permissions must map users to dApps, assets, and operations based on various conditions. The conditions can be generic and configurable via the PeerID user interface.

The blockchain will expose a generic interface to validate / verify with any external validator. The dApp can perform the calls with external services like a KYC verification application to receive a call back and then set relevant attributes to a given user.

PeerID should allow limiting users based on conditions set in the blockchain which are based on external validators (services like KYC, geo-location, etc.) The external conditions can be properties like is_member_of_facebook, is_MFA_enabled, etc.

3.1.5. Miscellaneous features

These features will be low priority, phase II features that will ensure additional controls and enhanced security.

  • unlinking third party services

  • Multi-Factor Authentication

  • Anti-Phishing features

3.2. Functional Requirements

3.2.1. Account creation

  • A user shall be able to create an account with any one of the following:

    • email address

    • Facebook id

    • Google id

  • A user shall be able to change their password

  • A user shall be able to import or export their Peerplays keys

  • A password recovery (forgot password) option shall be provided

3.2.2. dApp provisioning

  1. The first step of dApp creation is to create a corresponding blockchain account for the dApp. A simple UI shall be provided for creating the dApp account.

Aspects provisioned for the dApp account:

  • account name

  • access credentials - usernames, passwords, permissions

  • security tokens

  • federated logins with Google, Twitch, Youtube, Facebook, Steam, EPIC games, etc.

  • support for multi-factor authentication

4. Glossary

dApp - Decentralized Application. Just like a typical computer application, but with no centralized database, host, or distribution.

PBSA - Peerplays Blockchain Standards Association - For more information, see .

IdAM - Identity and Access Management - A framework of policies and technologies for ensuring that the right users have the appropriate access to technology resources.

SSO - Single Sign-On - An authentication scheme that allows a user to log in with a single set of credentials to any of several related, yet independent, applications. True single sign-on allows the user to log in once and access services without re-entering authentication factors.

PeerID - The IdAM and SSO blockchain middleware for the Peerplays blockchain.

MFA - Multi-Factor Authentication (encompassing two-factor authentication, or 2FA, along with similar terms) - An authentication method in which a user is granted access to an application only after successfully presenting two or more pieces of evidence (or factors) to an authentication mechanism.

KYC - Know Your Customer (or Client) - Guidelines in financial services that require organizations to make an effort to verify the identity, suitability, and risks involved with maintaining a business relationship.

bitcoin-operations-draft

btc_input_data_operation (Same as bitcoin_issue_operation in Sidechain)

This operation creates an object that stores the information about deposits for their further approval. Some minor changes will be required in its implementation i.e. the operation has to be signed by the active SONs holding more than 2/3rd of the votes.

This operation contains the following fields:

This operation is handled as follows:

1) Index is searched by id for vins same as the vin that is being added ( hash( string(hash_of_trx) + string(n_vout) ) ). 2) Id is calculated by the evaluator, since if it is passed in an operation, a potential attack vector opens: a valid ID for a different vin could be used to get approvals on another vin. 3) If nothing was found, a new btc_input_data_object object is created, storing the number of active SON members. son_id of the SON that sent the operation to set is also recorded in order to check confirmations by other SONs. 4) If set.size() > (2/3 + 1) * active_son_members_amount, btc_input_data_object object is considered confirmed (the consensus part). 5) Estimated fee index is searched for btc_fee_data_object by ID ( hash( string(btc_block_hash) ) ). 6) If no object was found, we create a btc_fee_data_object object, storing the number of active SON members. 7) Estimate fee map (key=son_id, value=fee) is checked for records about operation sender. If there is a record, handling stops. 8) If there are no records found in step 7, new information is recorded to the map. 9) If map.size() > (2/3 + 1) * active_son_members_amount, btc_fee_data_object is considered confirmed (the consensus part).

btc_withrawal_operation (Same as withdraw_pBTC_operation in the existing Sidechain feature)

This operation creates an object with information about a BTC withdrawal (btc_withdrawal_object). Some minor changes will be required in its implementation i.e. the operation has to be signed by the active SONs holding more than 2/3rd of the votes.

The fields are as follows:

This operation is handled as follows:

1) Validation is performed to make sure that the withdrawing PeerPlays account has enough pBTC for the withdrawal amount + fees (withdrawal amount + fee for son members + fee for Bitcoin transaction). 2) btc_withdrawal_object is created. It contains the following information: ID of the withdrawing account (account_id_type), Bitcoin address to withdraw to (string), amount of withdrawal in satoshis (uint64_t), used flag that indicates whether this object has been used (bool). 3) The amount from step 1 is burnt from the withdrawing user's balance 4) Confirmed objects are processed once every N block on PeerPlays (where N is a constant specified in the protocol. An example of N is 300 - since average blockTime on Bitcoin is ~10 minutes, and ~2 seconds on PeerPlays), which allows to minimize the tx fees by placing multiple withdrawals into one transaction. 5) On the node accepting a PeerPlays block a check is performed on its number (block_number % N == 0). If block_number = N, a btc_transaction_object, that contains a Bitcoin transaction. If inputs и withdrawals exceed the size of a Bitcoin transaction, another object is created containing a transaction that depends on the previous one. 6) On block acceptance an index storing the objects with btc_tx is checked. If it cointains an unsigned transaction, a signal for creating a son_member signature is emitted. 7) A Bitcoin transaction is emitted to Bitcoin blockchain once the object receives the required number of signatures.

btc_transaction_sign_operation (Same as btc_transaction_sign_operation in the existing Sidechain feature)

This operation serves to sign Bitcoin transactions by SONs. Some minor changes will be required in its implementation i.e. the operation has to be signed by the active SONs holding more than 2/3rd of the votes. It contains the following fields:

The process for signing a transaction is as follows: 1) When a signal from database::apply_block is called to create a signature for a Bitcoin transaction, a method from btc_sidechain_service is called. 2) btc_transaction_sign_operation is created storing the signature, and is broadcast on PeerPlays blockchain. evaluator class for this operation records btc_transaction_object of the signature, and, when the required number of signatures is collected ((2 / 3 + 1) * son_members_amount), sorts them in accordance with redeem script. The sorting is required since the keys in multisig script are handled in pre-defined order, and it is required that signatures are sorted in the same order (key - signature).

SON Configuration

1. Purpose

The purpose of this document is to outline the steps required by a Peerplays node operator to enable/disable Sidechain plugin in the Peerplays blockchain.

2. Scope

The functional requirement listed in this document will be limited to the configuration portion of the SON. This will outline the required steps that will be performed by the Peerplays node operator to enable/disable Sidechain plugin in the Peerplays blockchain from the command line. Also outlined here will be the sequence in which the required steps will be performed including:

  • any interactions with the user.

  • validations to ensure complete and accurate information gathering.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of SONs. As per the current implementation of Sidechain, a multisig bitcoin wallet will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multisig bitcoin wallet and will be required to sign any withdrawal transaction. When a SONs changes, the transaction signing key of the outgoing witness needs to be removed from the multisig bitcoin wallet and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SONs will be independent of the witnesses and don't need to be changed much often.

4. Process Overview

Described here is the process to configure the SON plugin in the Peerplays blockchain.

5. Context

The Peerplays blockchain will allow the node operators to enable/disable the Sidechain functionality on their node. They will have to stake PPY 50 to be able to register as an SON. As soon as the Sidechain functionality is enabled/disabled and the user vests 50 PPY, the Peerplays blockchain will add the node to its list of Sidechain enabled nodes and make the node operator available for SON voting. An SON enabled node will be able to operate as an SON only when it receives the votes required to become one of the top 15 SONs.

6. Flow Diagram

7. SON Commands

Any Peerplays node can become a SON irrespective of it is a witness or not. It can connect to a local or remote Bitcoin node and verify the transactions.

7.1 Enable SON

./programs/witness_node/witness_node --resync --replay --son-enable

This command will enable the SON functionality in the Peerplays node. The node will be registered in the peerplays blockchain as an SON enabled node. Peerplays users will be able to vote for this user to be an active SON. The node will be able to listen to the changes on the Bitcoin blockchain. An active SON can perform all the functionality of the sidechain once it has been voted into the top 15 SONs.

7.1.1. Pre-Conditions & Errors

The error messages are to be displayed in GUI wallet or cli_wallet or other programmatic means.

  1. The SON node should not be enabled and active for the same Peerplays account

  2. Trying to enable an already in enabled SON node will give the error message "SON is already enabled for the account_name."

  3. The account trying to enable SON should have a minimum balance of 50 PPY which has to be VESTED to become SON

  4. If the account is not having the minimum required balance, an error message "Minimum VESTING Balance for SON node activation is not available. Make sure that the account is funded with MINIMUM_VESTING_BALANCE"

  5. If a previous VESTED balance is available, it will not be considered to be the minimum VESTING BALANCE. This is to avoid accounts spamming the blockchain with SON-activate commands.

7.2. Disable SON

This section talks about permanently disabling SON.

./programs/witness_node/witness_node --resync --replay --son-disable

This command will disable the SON functionality in the Peerplays node and deregister the node in the peerplays blockchain as an SON enabled node. Any votes casted to the user to be an active SON will be reverted. The user will be able to claim their vested PPY after 2 days of deregistering their node.

7.1.2. Pre-Conditions & Errors

The error messages are to be displayed in GUI wallet or cli_wallet or other programmatic means.

  1. Only a SON node which is in "enabled state" can be disabled

  2. Trying to de-activate/disable a Peerplays node with SON not enabled will give the error message "SON is not enabled for account_name"

  3. If a SON is disabled and trying to move the VESTED funds before 2 days duration via any means should be prevented

API Requirements

All the v1 Sidechain APIs should work as it is. Except for those, an API to provide the list of SON enabled users will be required. The API should return the list in the following format:

CLI Wallet Command Requirements

These are new options to be added.

  1. list_sons: We need a command in the CLI Wallet similar to list_witnesses to get the list of SONs.

  2. list_active_sons: This command should provide a list of active SONs on the Peerplays blockchain.

1.0.0

The below sections help in understanding the ways of deployment and development.

Type

Name

Description

asset

fee

transaction fee for the operation

account_id_type

payer

SON account

vector<info_for_vin>

info_for_vins

a vector of vins

string

btc_block_hash

hash of a block on the side of BTC

uint64_t

estimated_feerate

estimate fee for Bitcoin transaction

Type

Name

Description

asset

fee

fee for the transaction on PeerPlays blockchain

account_id_type

payer

id of the PeerPlays account that initiates the withdrawal

string

data

bitcoin address, to which BTC is being withdrawn

uint64_t

amount

the amount of withdrawal in satoshis

Type

Name

Description

asset

fee

fee for the transaction on PeerPlays blockchain

account_id_type

payer

SON account that pays the fee

vector<vector>

signatures

Signatures for vins

Brainstorm planning
Brainstorm pre-work & ideas
In the context of SSO few items we are trying to do is:
The wallet
Brainstorm outcomes
commitment_type graphene::app::crypto_api::blind(
    const fc::ecc::blind_factor_type &blind, 
    uint64_t value)
blind_factor_type graphene::app::crypto_api::blind_sum(
    const std::vector<blind_factor_type> &blinds_in, 
    uint32_t non_neg)
range_proof_info graphene::app::crypto_api::range_get_info(
    const std::vector<char> &proof)
std::vector<char> graphene::app::crypto_api::range_proof_sign(
    uint64_t min_value, 
    const commitment_type &commit, 
    const blind_factor_type &commit_blind, 
    const blind_factor_type &nonce, 
    int8_t base10_exp, 
    uint8_t min_bits, 
    uint64_t actual_value
bool graphene::app::crypto_api::verify_sum(
    const std::vector<commitment_type> &commits_in, 
    const std::vector<commitment_type> &neg_commits_in, 
    int64_t excess)
verify_range_result graphene::app::crypto_api::verify_range(
    const fc::ecc::commitment_type &commit, 
    const std::vector<char> &proof)
verify_range_proof_rewind_result graphene::app::crypto_api::verify_range_proof_rewind(
    const blind_factor_type &nonce, 
    const fc::ecc::commitment_type &commit, 
    const std::vector<char> &proof)
Commitment Scheme

Requirements Specification

Requirements specification for Peerplays SONs

1. OBJECTIVE

Provide requirements for Sidechain Operating Nodes (SON). PIP (Peerplays Improvement Proposal) for the same is here : https://github.com/peerplays-network/pips/blob/master/pip-0005.md

  • Provide bi-directional exchange of value (tokens/coins) between multiple chains and Peerplays

2. Assumptions

  • Peerplays blockchain will be upgraded to support Ubuntu 18.04

  • GPoS will be merged and available

  • BOOST 1.67.0, Peerplays-FC with default versions of build tools like gcc, g++, cmake available on Ubuntu 18.04 will be used for the development.

  • A specific version / branch of the Peerplays blockchain will be provided by PBSA where all the unit test cases are running successfully

  • Voting UI will be made available

INTRODUCTION

In order to facilitate the transfer of token operations from the Peerplays blockchain to and from another blockchain Side Chain Operating nodes aka SONs is proposed. This mechanism will tie directly into GPOS in order to accomplish a full inter-blockchain communication mechanism. The scope of SONs is limited to transfer of value and not state across chains. The transfer of value will be bi-directional.

The core Peerplays blockchain will support SONs by having the plugin running SON receiver logic. The core of Peerplays blockchain will undergo only necessary changes, but not related to support of various external chains like EOS, Bitcoin and Ethereum. ie interface changes for support of new chains will happen at the SONs plugin and not at the Peerplays witness.

SONs will be elected through a voting mechanism making use of GPoS. A user interface allowing users to vote for SONs has to be created. This can be also incorporated to the wallet.

SON AS A PLUGIN

A Peerplays node, can enable or disable SON via the configuration file and restarting the node. When a node which wants to be an SON, node operator will enable and configure SON plugin, and register SON account. Disabling or enabling the plugin should not impact replaying the node. A SON becomes active participant based on the votes it receives. That is to say if a node just activates the plugin and registers SON account, but not receiving any votes, it will not be able to operate as a SON.

The SON plugin must have a mechanism to submit transactions it receives from side chains.

The SON plugin should enable API and programmatic interface which will help dApps or scripts to send transaction details from other chains to SONs. We must expose a generic interface which can be further extended for various blockchains. SONs must publish an API so that RPC requests for EOS, bitcoin & other chain related transactions to them. (Refer BTC Relay & PeaceRelay)

Transactions from Sidechain > SON Transaction Receiver > Processing and Signing of the Transaction by 2/3rd of the SONs > SON Transaction Submitter > Peerplays

As described above the SON must expose a generic transaction receiver with support for EOS, Bitshares, Bitcoin and Ethereum. A generic definition of the interface should be provided as part of the High Level Design. The generic interface should be capable of extending to support more chains in the future.

Enabling the SON plugin will not have any impact on a Peerplays witness node unless the node is also elected as a SON. The primary difference between the earlier Bitcoin sidechain implementation and SON is that no additional components from other chains will have to be operated by the SON nodes. This will ensure a lean system as opposed to the Peerplays nodes running various blockchains like Bitcoin and Ethereum Virtual Machines. This means no smart contracts written for say EVM will be executed in any of the Peerplays nodes irrespective whether they are witnesses, seed nodes or SONs.

VOTING

SONs will be elected using GPOS voting. The SONs will change depending on criteria like the votes received, taken out of circulation due to down time, planned maintenance etc. A minimum of 5 SONs should be available at any point in time for the SONs to be operational. The requirement of minimum 15 is needed to provide resilience. Transaction approval will require a minimum of 2/3rd approvals in any case.

As an SON enabled node, if my downtime exceeds 12 continuous hours, I should be automatically deregistered in the Peerplays blockchain as an SON enabled node and all the votes cast for me should be reverted. (Applicable only for unplanned downtime)

FEES

A daily rewards pool will be established for SONs that will be paid out daily based on transactions signed and weight of voting. Both approved and rejected transactions shall be included as part of the total transaction count. Recommended starting balance should be 200 PPY daily.

A SON, will be paid for providing my services through the blockchain & in PPY. The payments will be dispersed after each Maintenance cycle. All the transaction fee deducted from the bitcoin transactions for SONs should be deposited in a separate account just like the dividend-distribution-account.

KEY MANAGEMENT

To create a multisig address on Bitcoin, the signatures of all the SONs are required. The signatures of the top 2/3rd SONs in-terms of votes would be used while creating the Multisig account on the bitcoin blockchain. The top 2/3rd selection is thus an important end user controlled activity in the chain.

When a SON needs to perform maintenance, it will disable the node which will first rotate the keys used for the multi-signature wallet. This operation has to be detailed in the system architecture and design documents.

In the event of a SON part of the key management goes down abruptly, the funds under maintenance will be stuck until the SON comes back.

All bitcoin transactions in Peerplays blockchain get validated to ensure they are originated form the SONs only. Add validations on the Peerplays blockchain to check that the bitcoin transactions originated from the SONs only.

As soon as there is a change in the SON, his private key on the bitcoin address should be replaced by the private key of a new incoming SON OR we can simply delete the private key from the outgoing SON's account and add it to the new SON's account.

TODO: explore HTLC

TRANSACTION SIGNING & CONSENSUS

As captured early, we would need 15 SONs for the normal operation of the SON network. If the number of nodes goes below this number SONs should stop accepting new transactions. However if there are already existing multi-signature wallets & pegged assets or tokens issues in the Peerplays network those operation should continue. Any Transaction submitted by the SONs on the Peerplays blockchain should be signed by at least half + 1 SONs. This would ensure that a single SON cannot submit a malicious transaction on the blockchain.

SONs should create a distributed event bus sort of mechanism which should receive transaction details. If a SON receives the request for a transaction via an API, it must publish it to the event bus which the other SONs can read and process. This should be using a publisher - subscriber mechanism. If at any point in time a SON finds that a particular transaction is signed by 2/3rd of the SONs, that SON will post the transaction to the Peerplays blockchain. This will ensure that the Peerplays blockchain receives only those transactions which are signed by 2/3rd of the SONs. Upon receiving the transaction from the event bus, the SON will verify the transaction details with the appropriate blockchain & if the data on the source blockchain (sidechain) seems to be intact, the SON will sign the transaction and publish it back to the event bus. Any transaction signed by 2/3rd of the SONs will be marked dirty and will be taken out of the event bus. For the event bus, a ring buffer design pattern can be implemented. (refer: LMAX disruptor)

This will prevent any SON from creating a malicious transaction by running a malicious bitcoin node.

VESTING REQUIREMENTS

Nodes interested in becoming SONs must vest 50 amount of PPY. The PPY vested by SONs can't be claimed till 2 days after they have deregistered their SON node.

PERFORMANCE REQUIREMENTS FOR SONS

The performance of the SONs should be determined by their uptime as well as the errors that they make. Uptime & missed blocks or similar errors should be tracked and presented to the voters providing historical performance data to the voters.

Witnesses should have the power to freeze SON's account or blacklist SON. If an error on the part of an SON is not verifiable with a fork of the bitcoin blockchain then the witnesses should have the power to freeze his account or blacklist him.

ACCEPTANCE CRITERIA

  • performance: TPS, computational resource KPI must be defined

  • security audits: The ring buffer can be bombarded with event submissions. This must be carefully evaluated.

  • For each blockchain SONs are going to support, separate KPI (key performance indicators should be defined)

  • code peer review

User interaction and design

The end users are the Peerplays holders. They will be able to vote and select SONs. We need to prove a UI for the end users to engage in voting.

Open Questions

Question

Answer

Date Answered

How to address when a SON goes down abruptly and never comes back ?

What is the maximum allowed time for a SON to undergo maintenance ?

12 hours & after this the SON will be banned

What are the steps to announce maintenance ?

An explicit maintenance announcement command should be provided. This will trigger

rearrangement of multi-signature keys.

Out of Scope

TBD

SONs switchover scenarios

1. Purpose

The purpose of this document is to outline various scenarios in which SONs will be switched from the top 2/3rd and also among the top 15 minimum ACTIVE SONs.

2. Scope

The functional requirement listed in this document will be limited to the multi-sig key change scenarios only.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of SONs. As per the current implementation of Sidechain, a multisig bitcoin wallet will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multisig bitcoin wallet and will be required to sign any withdrawal transaction. When a SONs changes, the transaction signing key of the outgoing witness needs to be removed from the multisig bitcoin wallet and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SONs will be independent of the witnesses and don't need to be changed much often.

4. Process Overview

Various scenarios are outlined in the Scenarios section

5. Context

The SONs has a ranking & grouping. The ranking is depending on the total effective stake of the votes received. We can have infinitely many SONs and rankings. The top 15 nodes aka ACTIVE nodes are the ones which are mandated by the SON implementation. ie at any point of time, there has to be 15 nodes for the SON feature to be operational. Apart from the ACTIVE group of top 15, we also have a 2/3rd top ranked SONs in terms of votes which signs the transactions.

Any time there is a change to active SON list, a change to primary wallet scripts will be triggered. Therefore any change to active SONs list must result in creation of new primary wallet using public keys of SONs that remain active after the change. The reason for this is that primary wallet is created based on public keys of all active sons, when the composition of active SON list changes, it affects what keys are associated with the primary wallet.

At each maintenance intervals, list of candidates for active SONs is compared to list of current active SONs, if lists are different, list of current active SONs is understood to change and thus a new primary wallet must be generated.

6. Scenarios

Scenarios below are examples of changes that may impact active SONs list and thus trigger re-creation of primary wallet using public keys of SONs on active SONs list.

6.1 Ranking change within the top 2/3rd SONs

In this scenario the SONs will change their ranking and order but the top 2/3rd SONs will remain the same. This means, if there are 15 SONs and the 2/3rd is 10 SONs, the rank of the 10 SONs will be changed. But it will not have any impact on the multi-sig wallet. On using the list_sons will provide the new order.

During design, if possible its recommended to have invoke the immediate ranking change only in the case of a change involving the multi-signature key change. ie, this particular scenario can be ignored until the first deposit transaction happens. This will induce a slight delay in the display of ranking of the SONs for the reporting purposes.

6.2 Ranking Change due new votes resulting in the change of multi-wallet key

This scenario addresses the normal case where one or more of the top 2/3rd SONs loses votes and they moves out of the top 2/3rd.

An example scenario is with 15 ACTIVE SONs where the top 10 are forming the 2/3rd quorum. When one of them loses votes, an ACTIVE node or a node outside of TOP 15 ACTIVE nodes replaces its position.

This scenario would trigger:

  • creation of a new Bitcoin address

  • move the Bitcoin (BTC) balances to the new address which is controlled by the new set of top SONs

  • The deposit and transfer APIs of the SON should return new multi-signature wallet address

6.3 Ranking change - ACTIVE SON change

If an ACTIVE SON receives or loses votes, its effective stake can change. This can trigger the ranking change. The change will be executed at the next son_maintenance_interval` , ie 24 hours or during the next deposit/withdraw operation whichever comes first.

Ranking changes in the list of SONs must result in creation of new multi-signature wallet using public keys of new SONs. Balances are then transferred to the new address.

Note that any changes to list of SONs must result in new wallet being generated and balances transferred to new wallet address.

6.4 Ranking Change - Disabling an ACTIVE SON

If an ACTIVE SON disables its node, another node has to replace it.

This can trigger the ranking change. The change will be executed at the next son_maintenance_interval` , ie 24 hours or during the next deposit/withdraw operation whichever comes first.

Ranking changes in the list of SONs must result in creation of new multi-signature wallet using public keys of new SONs. Balances are then transferred to the new address.

6.5 Ranking change - an ACTIVE SON goes offline

In this scenario, an ACTIVE SON but not in the top 2/3rd in terms of cumulative votes received goes down.

  • SON goes down/offline

  • The SON network records this

  • Upon completion of 12 hours after the SON going down/offline event is recorded, the ranking change is triggered

  • The Ranking change will be executed on the first deposit transaction or once in 24 hours whichever comes first.

  • This approach is done at the cost of status change at the front-end, but to avoid unnecessary operations in the chain

Ranking changes in the list of SONs must result in creation of new multi-signature wallet using public keys of new SONs. Balances are then transferred to the new address.

6.6. A top 2/3rd SON goes offline

A high stake SON or a group of SONs goes offline without notice. This scenario or slowness is often observed during large scale internet routing attacks involving BGP poisoning or a data center maintenance where a group of servers becomes unreachable. (This often happens when certain German data center performs an upgrade or maintenance).

  • If we have ACTIVE SONs, and if need to perform a key change before the on the maintenance interval or before the next deposit transaction is requested, we can proceed with the change of keys

  • Upon such a change the funds has to be transferred to the new wallet created

  • The fund transfer will be possible if the remaining SONs who originally signed the transaction has enough authority (weight) to perform the withdraw operation on the old wallet

  • If the remaining SONs doesn't have enough control / weight to operate the multi-signature wallet, the funds will locked in the previous wallet until the necessary SONs becomes active. There seems to no way to address this. But, new deposits to the address will not be entrained as the deposit API will return new Bitcoin address.

If change of keys occurs for any SONs, this event must must result in creation of new multi-signature wallet using new SON keys. Balances are then transferred to the new address.

6.7 A top SON goes into maintenance - with key change

If a SON part of the multi-signature wallet creation with a large stake enough to trigger change in the keys, the maintenance mode should trigger a change in the ranking of the SONs & also a change in the keys.

To avoid frequent key changes, the key change can be handled upon the first deposit or withdrawal. The deposit and withdrawal operations to the SON should be made via calling respective APIs to make this possible.

IMPORTANT: The time taken for the wallet change operation should be captured and we need to take this account for fine tuning the strategy for key changes. This is something that we can't easily predict right now, but needs to test and verify.

This scenario must trigger creation of new wallet using SON public keys, and transfer of balance to new wallet address due to change in SON composition and public keys.

son-configuration

Purpose

The purpose of this document is to provide the design for the SON configuration.

Scope

This document describes the SON configuration based on the functional specifications Functional Specification - SON Configuration excluding the functionality that has been described in the Low Level Design document Wallet Commands for SON.

Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of SONs. As per the current implementation of Sidechain, a multisig bitcoin wallet will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every SON will have a bitcoin transaction signing key for this multisig bitcoin wallet and will be required to sign any withdrawal transaction. When a SONs changes, the transaction signing key of the outgoing SON needs to be removed from the multisig bitcoin wallet and the key of the incoming SON needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

Process Overview

Described here is the design for configuring the SONs on a node

Context

SONs have to be implemented as a plugin i.e. it shouldn't be mandatory for a node operator to register as an SON. It should be an option that can be chosen at the time of starting/restarting a node. Moreover, there shouldn't be an issue when replaying the chain even if the plugin is disabled. Also, the number of active SONs should be a chain parameter and the witnesses should be able to vote and change it.

son_plugin

son_plugin class should inherit from the graphene::app::plugin class and the methods plugin_set_program_options(), plugin_initialize(), plugin_startup() and plugin_shutdown() can be overridden to initialize the rpc client and to start/stop the bitcoin zmq listener.

son_api

All the APIs related to sidechain should be moved to the son_api class in the graphene::son namespace together with the son_plugin so that it is easy to maintain the project.

Register son_plugin

The SON plugin has to be registered in programs>witness_node>main.cpp using the register_plugin() method of node object if the options contain the string "son-enable" like below:

if(options.count("son-enable"))

node->register_plugin<son::son_plugin>()

This has to be done before calling the initialize_plugins() method of the node object.

Infrastructure
Development
[
    {
        serial_num: 1,
        id: 1.20.1,
        user: memphis123,
        rank: 1,
        about_url: www.memphis-node.com,
        sidechain_url: http://www.memphis-node.com/sidechain,
        is_active: true,
        votes: 23223245
    },
    {
        ....
    },
    ....
]
Files · support/docker · PBSA / Peerplays_1.0 / PeerID / PeerID-GUI · GitLabGitLab
Files · support/docker · PBSA / Peerplays_1.0 / PeerID / PeerID-backend · GitLabGitLab
Files · support/docker · PBSA / Peerplays_1.0 / PeerID / PeerID-GUI · GitLabGitLab
Files · support/docker · PBSA / Peerplays_1.0 / PeerID / PeerID-backend · GitLabGitLab
pbsa.info
(Figure 1: High-level design topology of a dApp)

Tournaments

get_tournaments_in_state

Get a list of tournament ids for upcoming tournaments

  • stateString: The tournament state

  • accountId:Account Id

All tournaments for the selected state.

get_registered_tournaments

Get a list of registered tournaments by account id.

  • accountId: Account Id.

All registered tournaments for an account.

get_tournaments

Get all tournaments between last_tournament_id and start_tournament_id.

  • last_tournament_id: The last tournament id

  • limit: The limit of tournaments to return.

  • start_tournament_id: The starting tournament id.

A list of all tournaments between last_tournament_id and start_tournament_id.

Deployment on a Linux Serve

Ubuntu

Configure the environment file

Configure the .env with the specified values:

Start the application (dev mode)

For a production environment build the static files:

After building the static files, you can host them using any web server.

PeerID-backend

configure the config/default.json and config/development.json files:

default.json

development.json

Start the application:

generic-sidechain-deposit-hld

Objective

This document is intended to outline generic design of deposit handling by Peerplays sidechain operating node. This interface will be extended to meet various other integrations.

Sidechain operating node will monitor target sidechain for events of interest, namely transfer of assets to a Peerplays address. When transfer happens, sidechain will process it, in order to pick up information needed to handle it. Handling deposits will create certain amount of tokens on a Peerplays network. This amount will match the amount of assets on target sidechain by predefined exchange rate.

Assumptions

  • Peerplays SON network is able to control (transfer or create) assets on Peerplays network, in order to send assets to a user account. E.g. Peerplays SONs network has control over an account on Peerplays network which holds initial ballance of Peerplays tokens, or is able to mine them to user account, or create them out of thin air and transfer them to user during deposit handling.

  • Peerplays SON network have full control over address/account on every supported sidechain. This address/account may be single signature wallet, multi-signature wallet, script, smart contract, or any other entity supported by a target sidechain, which is able to receive assets from users. This is the address where user should send his assets to, in order to get Peerplays tokens on Peerplays network.

  • Sidechain operating node has access to assets exchange rate list, containing exchange rates for every asset on every supported sidechain network. This list should be updateable by Peerplays network administrators.

  • Sidechain operating node has access to user accounts mapping list, containing user addresses on supported sidechains. Key value in this mapping is user’s Peerplays account. E.g. [PeerplaysAccount, BitcoinAccount, EthereumAccount, …]. All sidechain accounts should be created by user (e.g. user can enter them during registration as a Peerplays user). Account creation on target sidechain should not be handled by Peerplays, because of increased risk of handling their private keys. This list should be updateable by user.

Block diagram

Link to file

Description

  • As described in , when event of interest, transfer to a certain address on a target sidechain occurs, a sidechain handler will process it, and save the event data into Peerplays network for further processing.

  • Sidechain handler will identify user depositing funds, by searching transaction’s source address in user accounts mapping list, in order to find which Peerplays network address matches sidechain transaction source address. Peerplays network will transfer assets to this address (target address).

  • Sidechain handler will get the exchange rate from Exchange rate list, in order to calculate exact amount that needs to be transfered to the target address.

  • SONs will synchronize between them selves, by exchanging information about new transaction on sidechain and information about transfer that needs to be executed on Peerplays network. Once all active SONs have same information about transaction, randomly selected SON will create transaction and start singing process. Source address of this transfer will be SONs controlled account for issuing assets to users.

  • When first signature is added to transaction, signed transaction will be sent through SONs network, so that other SONs can sign it. At least 8 SONs needs to sign this transaction. We can also go with SONs with at least 2/3 of total weight signature, if that's supported by Bitshare. For now, it does not look like it is. Last SON signing transaction will broadcast it to the network. Tutorial on how to use multisig in Bitshares is here:

  • All sidechain specific functionalities will be implemented in sidechain handler.

  • All general functionalities will be implemented in sidechain handler base class.

Sequence diagram

Link to file

Same sequence diagram applies for all sidechain handlers. It shows interactions between components in a single sidechain handler.

SON Voting and Consensus

Purpose

The purpose of this document is to outline the steps required by a user to vote for an SON in the Peerplays blockchain and the consensus mechanism for SONs.

Scope

The functional requirement listed in this document will be limited to the voting and consensus portion of the SON. This will outline the required steps that will be performed by a user to vote for an SON in the Peerplays blockchain and their selection as active SONs. Also outlined here will be the sequence in which the required steps will be performed including:

  • any interactions with the user.

  • validations to ensure complete and accurate information gathering.

Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of SONs. As per the current implementation of Sidechain, a multisig bitcoin wallet will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multisig bitcoin wallet and will be required to sign any withdrawal transaction. When a SONs changes, the transaction signing key of the outgoing witness needs to be removed from the multisig bitcoin wallet and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SONs will be independent of the witnesses and don't need to be changed much often.

Process Overview

Described here is the process to vote for SONs in the Peerplays Blockchain.

Context

The Peerplays blockchain will allow the users to vote for the SON enabled node operators. The Peerplays blockchain should have a minimum of 15 active SON nodes. The user should be able to see a list of the SON enabled nodes and vote for up to 15 nodes. An SON enabled node will be able to operate as an active SON only when it receives the votes required to become one of the top 15 SONs. The number of active SON Nodes can be increased by the witnesses/advisor by making a change to the chain parameters. The active SONs will have corresponding bitcoin transaction signing keys in order to sign transactions for the Peerplays bitcoin multisig address on the bitcoin blockchain. When the active SONs change on the Peerplays blockchain, their corresponding bitcoin transaction signing keys are changed in the Peerplays bitcoin multisig address on the bitcoin blockchain.

Each SON when processing inter blockchain communications (IBC) will carry a percentage of weight in the signing based on the votes they have received. Every IBC request will require signed consensus by at least ⅔ of the Active Cast Weighted (ACW) Votes for the SONs. Active Cast Weighted votes means the votes casted to active SONs by users who have staked some PPY weighted by their staked PPY.

If an SON enabled node's downtime exceeds 12 continuous hours, it should be automatically deregistered in the Peerplays blockchain as an SON enabled node and all the votes cast for me should be reverted.

If an SON decides to stop operating the node by disabling the SON plugin, any votes cast to him will be removed and another SON will take his place.

Flow Diagram

SON Voting Command

The below command from the CLI wallet will be used to vote for SONs: vote_for_son <voting_account> <son> <approve> <broadcast>

  • voting_account_id: the name or id of the account who is voting with their shares

  • son: the name or id of the son's owner account

  • approve: true if you wish to vote in favor of that son, false to remove your vote in favor of that son

  • broadcast: true if you wish to broadcast the transaction

draw.io
https://drive.google.com/file/d/14HFGLqD8IV3ics1ojFcZ2xC6hRtFXLck/view?usp=sharing
Generic Sidechain High Level Design
https://github.com/bitshares/bitshares1-core/wiki/multisig
draw.io
https://drive.google.com/file/d/17kbez7C1Djaj-2AgyEzQ1Z-5CrSZ5wZE/view?usp=sharing
Apis.instance().db_api().exec('get_tournaments_in_state', [stateString, accountId])
Apis.instance().db_api().exec('get_registered_tournaments', [accountId, 100])
 _ws.Apis.instance().db_api().exec('get_tournaments', [last_tournament_id, limit, start_tournament_id])
ChainStore.prototype.getTournamentIdsInState = function getTournamentIdsInState(accountId, stateString) {
    var _this7 = this;

    var tournamentIdsForThisAccountAndState = void 0;
    var tournamentIdsForThisAccount = this.tournament_ids_by_state.get(accountId);

    if (tournamentIdsForThisAccount === undefined) {
      tournamentIdsForThisAccountAndState = new _immutable2.default.Set();
      tournamentIdsForThisAccount = new _immutable2.default.Map().set(stateString, tournamentIdsForThisAccountAndState);
      this.tournament_ids_by_state = this.tournament_ids_by_state.set(accountId, tournamentIdsForThisAccount);
    } else {
      tournamentIdsForThisAccountAndState = tournamentIdsForThisAccount.get(stateString);

      if (tournamentIdsForThisAccountAndState !== undefined) {
        return tournamentIdsForThisAccountAndState;
      }

      tournamentIdsForThisAccountAndState = new _immutable2.default.Set();
      tournamentIdsForThisAccount = tournamentIdsForThisAccount.set(stateString, tournamentIdsForThisAccountAndState);
      this.tournament_ids_by_state = this.tournament_ids_by_state.set(accountId, tournamentIdsForThisAccount);
    }

    _ws.Apis.instance().db_api().exec('get_tournaments_in_state', [stateString, 100]).then(function (tournaments) {
      var originalTournamentIdsInState = _this7.tournament_ids_by_state.getIn([accountId, stateString]);
      // call updateObject on each tournament, which will classify it
      tournaments.forEach(function (tournament) {
        /**
         * Fix bug: we cant update tournament_ids_by_state if objects_by_id has a tournament
         */
        if (!originalTournamentIdsInState.get(tournament.id)) {
          _this7.clearObjectCache(tournament.id);
        }

        _this7._updateObject(tournament);
      });

      var tournament_id = _this7.tournament_ids_by_state.getIn([accountId, stateString]);

      if (tournament_id !== originalTournamentIdsInState) {
        _this7.notifySubscribers();
      }
    });
    return tournamentIdsForThisAccountAndState;
  };
ChainStore.prototype.getRegisteredTournamentIds = function getRegisteredTournamentIds(accountId) {
    var _this8 = this;

    var tournamentIds = this.registered_tournament_ids_by_player.get(accountId);

    if (tournamentIds !== undefined) {
      return tournamentIds;
    }

    tournamentIds = new _immutable2.default.Set();
    this.registered_tournament_ids_by_player = this.registered_tournament_ids_by_player.set(accountId, tournamentIds);

    _ws.Apis.instance().db_api().exec('get_registered_tournaments', [accountId, 100]).then(function (registered_tournaments) {
      var originalTournamentIds = _this8.registered_tournament_ids_by_player.get(accountId);
      var newTournamentIds = new _immutable2.default.Set(registered_tournaments);

      if (!originalTournamentIds.equals(newTournamentIds)) {
        _this8.registered_tournament_ids_by_player = _this8.registered_tournament_ids_by_player.set(accountId, newTournamentIds);
        _this8.notifySubscribers();
      }
    });

    return tournamentIds;
  };
ChainStore.prototype.getTournaments = function getTournaments(last_tournament_id) {
    var _this20 = this;

    var limit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
    var start_tournament_id = arguments[2];

    return _ws.Apis.instance().db_api().exec('get_tournaments', [last_tournament_id, limit, start_tournament_id]).then(function (tournaments) {
      var list = _immutable2.default.List();

      _this20.setLastTournamentId(null);

      if (tournaments && tournaments.length) {
        list = list.withMutations(function (l) {
          tournaments.forEach(function (tournament) {
            if (!_this20.objects_by_id.has(tournament.id)) {
              _this20._updateObject(tournament);
            }

            l.unshift(_this20.objects_by_id.get(tournament.id));
          });
        });
      }

      return list;
    });
  };

Privacy Mode

Privacy Mode

set_key_label

These methods are used for stealth transfers This method can be used to set a label for a public key

Note: No two keys can have the same label.

bool graphene::wallet::wallet_api::set_key_label(
    public_key_type key, 
    string label)
  • key: a public key

  • label: a user-defined string as label

True if the label was set, otherwise false

get_key_label

Get label of a public key.

string graphene::wallet::wallet_api::get_key_label(
    public_key_type key)const
  • key: a public key

The label if already set by set_key_label(), or an empty string if not set

get_public_key

Get the public key associated with a given label

public_key_type graphene::wallet::wallet_api::get_public_key(
    string label)const
  • label: a label

The public key associated with the given label.

get_blind_accounts

Get all blind accounts.

map<string, public_key_type> graphene::
wallet
::
wallet_api
::get_blind_accounts()const

All blind accounts

get_my_blind_accounts

Get all blind accounts for which this wallet has the private key.

map<string, public_key_type> graphene::wallet::wallet_api::get_my_blind_accounts()const

All blind accounts for which this wallet has the private key.

get_blind_balances

Return the total balances of all blinded commitments that can be claimed by the given account key or label.

vector<asset> graphene::wallet::wallet_api::get_blind_balances(
    string key_or_label)
  • key_or_label: a public key in Base58 format or a label

The total balances of all blinded commitments that can be claimed by the given account key or label

create_blind_account

Generates a new blind account for the given brain key and assigns it the given label

public_key_type graphene::
wallet
::
wallet_api
::create_blind_account(string label, string brain_key)
  • label: a label

  • brain_key: the brain key to be used to generate a new blind account

The public key of the new account

transfer_to_blind

Transfers a public balance from from_account_id_or_name to one or more blinded balances using a stealth transfer.

blind_confirmationgraphene::wallet::wallet_api::transfer_to_blind(
    string from_account_id_or_name, 
    string asset_symbol, 
    vector<pair<string, string>> to_amounts, 
    bool broadcast = false)
  • from_account_id_or_name: ID or name of an account to transfer from

  • asset_symbol: symbol or ID of the asset to be transferred

  • to_amounts: map from key or label to amount

  • broadcast: true to broadcast the transaction on the network

A blind confirmation

transfer_from_blind

Transfers funds from a set of blinded balances to a public account balance.

blind_confirmationgraphene::wallet::wallet_api::transfer_from_blind(
    string from_blind_account_key_or_label, 
    string to_account_id_or_name, 
    string amount, 
    string asset_symbol, 
    bool broadcast = false)
  • from_blind_account_key_or_label: a public key in Base58 format or a label to transfer from

  • to_account_id_or_name: ID or name of an account to transfer to

  • amount: the amount to be transferred

  • asset_symbol: symbol or ID of the asset to be transferred

  • broadcast: true to broadcast the transaction on the network

A blind confirmation.

blind_transfer

Transfer from one set of blinded balances to another.

blind_confirmationgraphene::wallet::wallet_api::blind_transfer(
    string from_key_or_label, 
    string to_key_or_label, 
    string amount, 
    string symbol, 
    bool broadcast = false)
  • from_key_or_label: a public key in Base58 format or a label to transfer from

  • to_key_or_label: a public key in Base58 format or a label to transfer to

  • amount: the amount to be transferred

  • symbol: symbol or ID of the asset to be transferred

  • broadcast: true to broadcast the transaction on the network

A blind confirmation

blind_history

Get all blind receipts to/form a particular account.

vector<blind_receipt> graphene::wallet::wallet_api::blind_history(
    string key_or_account)
  • key_or_account: a public key in Base58 format or an account

All blind receipts to/form the account.

receive_blind_transfer

Given a confirmation receipt, this method will parse it for a blinded balance and confirm that it exists in the blockchain. If it exists then it will report the amount received and who sent it.

blind_receipt graphene::
wallet
::
wallet_api
::receive_blind_transfer(string confirmation_receipt, string opt_from, string opt_memo)
  • confirmation_receipt: a base58 encoded stealth confirmation

  • opt_from: if not empty and the sender is a unknown public key, then the unknown public key will be given the label opt_from

  • opt_memo: a self-defined label for this transfer to be saved in local wallet file

A blind receipt.

Wallet Calls

Wallet Calls

is_new

Checks whether the wallet has just been created and has not yet had a password set.

Calling set_password will transition the wallet to the locked state.

bool graphene::wallet::wallet_api::is_new()const

True if the wallet is new.

is_locked

Checks whether the wallet is locked (is unable to use its private keys).

This state can be changed by calling lock() or unlock().

bool graphene::wallet::wallet_api::is_locked()const

True if the wallet is locked

lock

Locks the wallet immediately.

void graphene::wallet::wallet_api::lock()

unlock

Unlocks the wallet.

The wallet remain unlocked until the lock is called or the program exits.

When used in command line, if typed “unlock” without a password followed, the user will be prompted to input a password without echo.

void graphene::wallet::wallet_api::unlock(
    string password)
  • password: the password previously set with set_password()

set_password

Sets a new password on the wallet.

The wallet must be either ‘new’ or ‘unlocked’ to execute this command.

When used in command line, if typed “set_password” without a password followed, the user will be prompted to input a password without echo.

void graphene::wallet::wallet_api::set_password(
    string password)
  • password: a new password

dump_private_keys

Dumps all private keys owned by the wallet.

The keys are printed in WIF format. You can import these keys into another wallet using import_key()

map<public_key_type, string> graphene::wallet::wallet_api::dump_private_keys()

A _**_map containing the private keys, indexed by their public key

import_key

Imports the private key for an existing account.

The private key must match either an owner key or an active key for the named account.

See also **dump_private_keys()

bool graphene::wallet::wallet_api::import_key(
    string account_name_or_id, 
    string wif_key)
  • account_name_or_id: the account owning the key

  • wif_key: the private key in WIF format

true if the key was imported

import_accounts

Imports accounts from a BitShares 0.x wallet file. Current wallet file must be unlocked to perform the import.

map<string, bool> graphene::wallet::wallet_api::import_accounts(
    string filename, 
    string password)
  • filename: the BitShares 0.x wallet file to import

  • password: the password to encrypt the BitShares 0.x wallet file

A map containing the accounts found and whether imported.

import_account_keys

Imports from a BitShares 0.x wallet file, find keys that were bound to a given account name on the BitShares 0.x chain, rebind them to an account name on the 2.0 chain. Current wallet file must be unlocked to perform the import.

bool graphene::wallet::wallet_api::import_account_keys(
    string filename, 
    string password, 
    string src_account_name, 
    string dest_account_name)
  • filename: the BitShares 0.x wallet file to import

  • password: the password to encrypt the BitShares 0.x wallet file

  • src_account_name: name of the account on BitShares 0.x chain

  • dest_account_name: name of the account on BitShares 2.0 chain, can be same or different to src_account_name

Whether the import has succeeded

import_balance

This call will construct transaction(s) that will claim all balances controlled by wif_keys and deposit them into the given account.

vector<signed_transaction> graphene::wallet::wallet_api::import_balance(
    string account_name_or_id, 
    const vector<string> &wif_keys, 
    bool broadcast)
  • account_name_or_id: name or ID of an account that to claim balances to

  • wif_keys: private WIF keys of balance objects to claim balances from

  • broadcast: true to broadcast the transaction on the network

suggest_brain_key

Suggests a safe brain key to use for creating your account. create_account_with_brain_key() requires you to specify a ‘brain key’, a long passphrase that provides enough entropy to generate cryptographic keys.

This function will suggest a suitably random string that should be easy to write down (and, with effort, memorize).

brain_key_info graphene::wallet::wallet_api::suggest_brain_key()const

A suggested brain_key

get_transaction_id

This method is used to convert a JSON transaction to its transacting ID.

transaction_id_type graphene::wallet::wallet_api::get_transaction_id(
    const signed_transaction &trx)const
  • trx: a JSON transaction

The ID (hash) of the transaction.

get_private_key

Get the WIF private key corresponding to a public key. The private key must already be in the wallet.

string graphene::wallet::wallet_api::get_private_key(
    public_key_type pubkey)const
  • pubkey: a public key in Base58 format

The WIF private key

load_wallet_file

Loads a specified Graphene wallet.

The current wallet is closed before the new wallet is loaded.

Important: This does not change the filename that will be used for future wallet writes, so this may cause you to overwrite your original wallet unless you also call set_wallet_filename()

bool graphene::wallet::wallet_api::load_wallet_file(
    string wallet_filename = "")
  • wallet_filename: the filename of the wallet JSON file to load. If wallet_filename is empty, it reloads the existing wallet file.

True if the specified wallet is loaded.

normalize_brain_key

Transforms a brain key to reduce the chance of errors when re-entering the key from memory.

This takes a user-supplied brain key and normalizes it into the form used for generating private keys. In particular, this upper-cases all ASCII characters and collapses multiple spaces into one.

string graphene::wallet::wallet_api::normalize_brain_key(
    string s)const
  • s: the brain key as supplied by the user

The brain key in its normalized form.

save_wallet_file

Saves the current wallet to the given filename.

Important: This does not change the wallet filename that will be used for future writes, so think of this function as ‘Save a Copy As…’ instead of ‘Save As…’. Use set_wallet_filename() to make the filename persist.

void graphene::wallet::wallet_api::save_wallet_file(
    string wallet_filename = "")
  • wallet_filename: the filename of the new wallet JSON file to create or overwrite. If wallet_filename is empty, save to the current filename.

changeover and SON maintenance scenarios lld

1. Purpose

The purpose of this document is to outline the existing changeover process in Sidechain and list the SON maintenance scenarios (both user-triggered and abruptly downed servers).

2. Scope

The design listed in this document is limited to the listing of the scenarios that can arise due to maintenance and how to tackle the PW changes arising out of the change of SONs.

This document also outlines the current implementation of Sidechain and whats missing from that implementation and how it is different from the current SONs requirement.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. How it all works

There are two types of bitcoin addresses,

  1. PW Address

  2. Deposit Address of a User.

Following are the list of steps needed for a user to transfer BTC,

  1. A PW Address is created which acts as a global address holding all the user funds.

  2. A user issues create_bitcoin_address and gets a bitcoin address multi-signed by SONs ( 10-of-15 multi-sig Proposed currently ). This is called Deposit Address.

  3. The user transfers BTC funds to the deposit address.

  4. Bitcoin block listener catches the transaction if any vout has any of the deposit addresses.

  5. A proposal to send the BTC from the user Deposit Address to PW address is initiated by SONs and if approved, a bitcoin transaction signed by the top 2/3 SONs is sent out.

  6. After receiving confirmation from Bitcoin ( 6 blocks confirmation ) a proposal to issue pBTC to the user's account is initiated by SONs.

  7. If the proposal is approved, pBTC is issued to the user's peerplays account.

  8. External miner fee is also taken into consideration for the bitcoin transaction initiated from deposit address to PW address apart from fees of proposals initiated.

5. Current Sidechain Implementation

In the current sidechain implementation, Witnesses act as signatories and follow 5-of-15 multi-sig model.

Each witness has the same weight associated with its signing key.

PW address is changed if more than 5 witnesses are voted out which is very unlikely.

All the user deposit addresses are also needed to be changed along with PW address.

More info can be found about sidechain implementation on this site.

6. Challenges for the proposed SONs Implementation

The current proposal of SONs takes DPOS mechanism into consideration for associating weights with signatures of each SON.

Based on the votes tallied each SON will have a different weight of the signature in each bitcoin multi-sig address (10-of-15 multi-sig) that's issued on Peerplays network.

6.1 Disadvantages with current weighted model

  1. With the weighted signing, if any of the SONs can accumulate enough weight which is more than 1/3 (34%), we will have a single point of failure model.

  2. If such a SON ( which has more than 1/3 or at least 34% weight) goes down abruptly, there is no other way but to change the PW address.

  3. PW multi-sig address might need to be changed multiple times in this model because of the weights.

  4. Loss of miners fee associated with the transfer of BTC from old PW address to new PW address.

6.2 Advantages with equally weighted SONs model

  1. With 10-of-15 multi-sig equally weighted model, it is almost impossible for more than 5 SONs to go down at a time. Thus very less chance of SON network stall.

  2. PW multi-sig address need not be changed multiple times which can save us the miner fee that's charged for sending BTC from old PW to latest PW.

7. Scenarios Captured for PW address change

The idea is that immediately after the initial hard fork with SON change, a new PW address is created and a buffer amount of bitcoins are sent to it.

This buffer is to offset the mining fee associated with the transfer of BTC from old PW address to the new PW address.

7.1 De-Register issued by Active SON user

7.1.1 SON weight < ( 1/3 or 33.33% ) – PW Address remains the same.

If the active SON weight is less than the 1/3 or 33.33% then there is no need to change the PW address.

After the maintenance interval, a new set of active SONs are active but the PW address remains the same.

==> Transfers from user deposit addresses to PW Address goes on as usual.

7.1.2 SON weight > ( 1/3 or 33.33% ) – PW Address changes.

We will wait until the maintenance interval, tally votes again during the maintenance interval.

If the active SON weight is greater than the 1/3 or 33.33% then a new PW address is assigned.

Funds from the old PW Address are transferred to the new PW Address.

The SON is removed from the active list.

==> All the transactions for transferring BTC from Deposit address to PW Address are stuck till the SON node comes back.

==> Deposit addresses have to be changed to be signed by the new set of SONs.

7.2 De-Register issued by Inactive SON user – PW Address remains the same.

If an inactive SON is de-registered, there is no need to change the PW Address.

After the maintenance interval, we can allow the user to claim his vesting balance after 2 days.

==> Transfers from user deposit addresses to PW Address goes on as usual.

7.3 Active SON Abruptly Down

7.3.1 SON weight < ( 1/3 or 33.33% ) – PW Address remains the same.

If the active SON weight is less than the 1/3 or 33.33% then there is no need to change the PW address.

After the maintenance interval, a new set of active SONs are active but the PW address remains the same.

==> Transfers from user deposit addresses to PW Address goes on as usual.

7.3.2 SON weight > ( 1/3 or 33.33% ) – PW Address changes.

We will wait until the maintenance interval, tally votes again during the maintenance interval.

If the active SON weight is greater than the 1/3 or 33.33% then a new PW address is assigned.

Funds from the old PW Address are transferred to the new PW Address.

The SON is removed from the active list.

All the transactions for transferring BTC from Deposit address to PW Address are stuck till the SON node comes back.

==> All the transactions for transferring BTC from Deposit address to PW Address are stuck till the SON node comes back.

==> Deposit addresses have to be changed to be signed by the new set of SONs.

7.4 Inactive SON(s) Abruptly Down – PW Address remains the same.

If an inactive SON is down, there is no need to change the PW Address.

After the maintenance interval, we can allow the user to claim his vesting balance after 2 days.

==> Transfers from user deposit addresses to PW Address goes on as usual.

7.5 Multiple Active SONs Abruptly Down

7.5.1 Sum of the downed SONs Weight < ( 1/3 or 33.33% ) – PW Address remains the same.

If the weight of SONs went down is less than the 1/3 or 33.33% then there is no need to change the PW address.

After the maintenance interval, a new set of active SONs are active but the PW address remains the same.

==> Transfers from user deposit addresses to PW Address goes on as usual.

7.5.2 Sum of the downed SONs weight > ( 1/3 or 33.33% ) – PW Address changes.

We will wait until the maintenance interval, tally votes again during the maintenance interval.

If the sum of the weight of the active SONs that are down is greater than the 1/3 or 33.33% then a new PW address is assigned.

Funds from the old PW Address are transferred to the new PW Address.

The SONs are removed from the active list.

All the transactions for transferring BTC from Deposit address to PW Address are stuck till one or more SON nodes comes back which allow us to hit the required threshold weight of 2/3 or 66.67%.

==> All the transactions for transferring BTC from Deposit address to PW Address are stuck till one or more SON nodes comes back which allow us to hit the required threshold weight of 2/3 or 66.67%.

==> Deposit addresses have to be changed to be signed by the new set of SONs.

7.6 Active SON ( weight > 1/3 or 33.33% ) goes down before Bitcoin transaction is confirmed – PW Address changes.

If an active SON with enough weight to stall the SON network goes down in the middle of transfer of BTC from user's deposit address to PW address and then the transaction is not confirmed on Bitcoin network, then the funds are stuck in the user deposit address till the SON comes back.

During maintenance, a new set of SONs are elected.

PW Address is changed with new signatories.

Infrastructure Docs
Community Docs
git clone https://gitlab.com/PBSA/PeerplaysIO/tools-libs/peerid/peerid-gui.git
cd peerid-gui
npm install
touch .env
DEV_API_ROUTE='http://example.com/'
PRODUCTION_API_ROUTE='http://examples.com/'

DEV_BASE_ROUTE='http://example.com/api'
PRODUCTION_BASE_ROUTE='http://examples.com/api'

BLOCKCHAIN_ENDPOINTS='wss://example-endpoint.com/api'

PEERPLAYS_USD_ASSET_ID='1.3.0'
PEERPLAYS_ESCROW_ACCOUNT_ID='1.2.23'
PEERPLAYS_PAYMENT_ACCOUNT_ID='1.2.21'
npm start
npm run build
git clone https://gitlab.com/PBSA/PeerplaysIO/tools-libs/peerid/peerid-backend
cd peerid-backend
npm install
{
  "logLevel": "trace",
  "db": {
    "user": "",
    "password": "",
    "host": "127.0.0.1",
    "port": "5432",
    "database": "peerid"
  },
  "swagger": {
    "host": "virtserver.swaggerhub.com",
    "schemes": [
      "https"
    ]
  },
  "sessionSecret": "sessionSecret",
  "cors": true,
  "port": 3000,
  "google": {
    "clientId": "",
    "clientSecret": ""
  },
  "facebook": {
    "clientId": "",
    "clientSecret": ""
  },
  "discord": {
    "clientId": "",
    "clientSecret": ""
  },
  "raven": {
    "enabled": false,
    "url": ""
  },
  "mailer": {
    "host": "smtp.gmail.com",
    "port": 587,
    "secure": false,
    "auth": {
      "user": "",
      "pass": ""
    },
    "sender": "",
    "tls": {
        "rejectUnauthorized": false
    }
  },
  "frontendUrl": "http://localhost:8082",
  "backendUrl": "http://localhost:3000",
  "frontendCallbackUrl": "http://localhost:8082/callback",
  "peerplays": {
    "peerplaysWS": "wss://irona.peerplays.download/api",
    "peerplaysFaucetURL": "https://irona-faucet.peerplays.download/api/v1/accounts",
    "referrer": "1.2.0",
    "feeAssetId": "1.3.0",
    "paymentAccountID": "1.2.21",
    "paymentAccountWIF": "5HttHcgL2NgFc5XsFY8bs51VehVDS2Tb4NGkRuwjJ6v6Mq7eC7S"
  }
}
{
  "logLevel": "trace",
  "db": {
    "user": "",
    "password": "",
    "host": "127.0.0.1",
    "port": "5432",
    "database": "peerid"
  },
  "swagger": {
    "host": "virtserver.swaggerhub.com",
    "schemes": [
      "https"
    ]
  },
  "sessionSecret": "sessionSecret",
  "cors": true,
  "port": 3000,
  "google": {
    "clientId": "",
    "clientSecret": ""
  },
  "facebook": {
    "clientId": "",
    "clientSecret": ""
  },
  "discord": {
    "clientId": "",
    "clientSecret": ""
  },
  "raven": {
    "enabled": false,
    "url": ""
  },
  "mailer": {
    "host": "smtp.gmail.com",
    "port": 587,
    "secure": false,
    "auth": {
      "user": "",
      "pass": ""
    },
    "sender": "",
    "tls": {
        "rejectUnauthorized": false
    }
  },
  "frontendUrl": "http://localhost:8082",
  "backendUrl": "http://localhost:3000",
  "frontendCallbackUrl": "http://localhost:8082/callback",
  "peerplays": {
    "peerplaysWS": "wss://irona.peerplays.download/api",
    "peerplaysFaucetURL": "https://irona-faucet.peerplays.download/api/v1/accounts",
    "referrer": "1.2.0",
    "feeAssetId": "1.3.0",
    "paymentAccountID": "1.2.21",
    "paymentAccountWIF": "5HttHcgL2NgFc5XsFY8bs51VehVDS2Tb4NGkRuwjJ6v6Mq7eC7S"
  }
}
npm start

user-sidechain-addresses-mapping

User sidechain address mapping is a component containing sidechain addresses belonging to a particular Peerplays user account. User sidechain addresses mapping is used in sidechain handler, a component of a SON plugin, for filtering events reported by listener, to identify the transactions of interest.

Transactions of interest are:

  • For deposit handling, transfer on a sidechain network where from address is listed in user sidechain addresses mapping and to address is a sidechain address controlled by SON network (Primary wallet).

  • For withdrawal handling, still to decide… E.g. transfer on a Peerplays network where from address is listed in user sidechain addresses mapping and to address is a address on a Peerplays network controlled by SON network (Primary wallet).

Requirements

  • In database terms, user sidechain address mapping is one-to-many relation, where one user can have multiple addresses belonging to him on a different blockchain. No duplicates are allowed, so user can register only one address per sidechain.

  • User sidechain address mapping contains records with Peerplays account as a reference to user, and a string representing the address/account on a target sidechain.

  • User addresses can be added, deleted and updated. Update and delete may be executed only by user to owning the record.

  • User sidechain address mapping operations

    • add_user_sidechain_address - adds user sidechain address

    • update_user_sidechain_address - updates user sidechain address

    • delete_user_sidechain_address - deletes user sidechain address

  • User sidechain address mapping wallet functions

    • add_user_sidechain_address - adds user sidechain address

    • update_user_sidechain_address - updates user sidechain address

    • delete_user_sidechain_address - deletes user sidechain address

    • get_user_sidechain_address - gets a single user sidechain address (by user account id and network)

    • list_user_sidechain_address - lists all users sidechain addresses

    • get_sidechain_addresses - gets a list of all addresses belonging to a given sidechain network

Example of user sidechain addresses mapping

Following table shows user sidechain addresses mapping

Implementation

Consider the following code as a suggestion, not as a 100% completed ad working implementation. Syntax errors may be present.

Following declaration needs to be moved from SON plugin, to the core:

enum networks {

bitcoin,

eos,

ethereum

};

User sidechain address object:

class user_sidechain_address_object : public graphene::db::abstract_object<user_sidechain_addresses_object> {

uint32_t id; // Primary key

account_id_type user; // User owning the address

network network; // Network to whom address belongs

std::string address; // Sidechain address

}

User sidechain address mapping index:

struct by_network;

struct by_user_network;

using user_sidechain_address_multi_index_type = multi_index_container<

user_sidechain_address_object,

indexed_by<

ordered_unique< tag<by_id>,

member<object, object_id_type, &object::id>

>,

ordered_unique< tag<by_network>,

member<user_sidechain_address_object, network, &user_sidechain_address_object::network>

>,

ordered_unique< tag<by_user_network>,

composite_key<user_sidechain_address_object,

member<user_sidechain_address_object, account_id_type, &user_sidechain_address_object::user>,

member<user_sidechain_address_object, network, &user_sidechain_address_object::network>,

>

>

>

>;

  • User sidechain address mapping should be indexed at least by:

    • Primary key index

    • Network field

    • User and network fields

User sidechain address create operations:

struct user_sidechain_address_create_operation : public base_operation

{

uint32_t id; // Primary key

account_id_type user; // User owning the address

network network; // Network to whom address belongs

std::string address; // Sidechain address

void validate()const;

};

Validation should check that the item is not duplicated, by checking user and network fields.

User sidechain address update operations:

struct user_sidechain_address_update_operation : public base_operation

{

uint32_t id; // Primary key

account_id_type user; // User owning the address

network network; // Network to whom address belongs

std::string address; // Sidechain address

void validate()const;

};

Validation should check that the item with the given id exists in the list.

User sidechain address delete operation:

struct user_sidechain_address_delete_operation : public base_operation

{

uint32_t id; // Primary key

void validate()const;

};

Validation should check that the item with the given id exists in the list.

Appropriate evaluators must be implemented too.

Trading Calls

Trading Calls

sell_asset

Place a limit order attempting to sell one asset for another.

Buying and selling are the same operation on Peerplays; if you want to buy PPY with BTC, you should sell BTC for PPY.

The blockchain will attempt to sell the symbol_to_sell for as much symbol_to_receive as possible, as long as the price is at least min_to_receive / amount_to_sell.

In addition to the transaction fees, market fees will apply as specified by the issuer of both the selling asset and the receiving asset as a percentage of the amount exchanged.

If either the selling asset or the receiving asset is whitelist restricted, the order will only be created if the seller is on the whitelist of the restricted asset type.

Market orders are matched in the order they are included in the block chain.

  • seller_account: the account providing the asset being sold, and which will receive the proceeds of the sale.

  • amount_to_sell: the amount of the asset being sold to sell (in nominal units, for example 0.5 for half of a PPY)

  • symbol_to_sell: the name or id of the asset to sell

  • min_to_receive: the minimum amount you are willing to receive in return for selling the entire amount_to_sell

  • symbol_to_receive: the name or id of the asset you wish to receive

  • timeout_sec: if the order does not fill immediately, this is the length of time the order will remain on the order books before it is cancelled and the un-spent funds are returned to the seller’s account

  • fill_or_kill: if true, the order will only be included in the blockchain if it is filled immediately; if false, an open order will be left on the books to fill any amount that cannot be filled immediately.

  • broadcast: true to broadcast the transaction on the network

The signed transaction selling the funds.

borrow_asset

Borrow an asset or update the debt/collateral ratio for the loan.

This is the first step in shorting an asset.

Call to complete the short.

  • borrower_name: the name or id of the account associated with the transaction.

  • amount_to_borrow: the amount of the asset being borrowed. Make this value negative to pay back debt.

  • asset_symbol: the symbol or id of the asset being borrowed.

  • amount_of_collateral: the amount of the backing asset to add to your collateral position. Make this negative to claim back some of your collateral. The backing asset is defined in the bitasset_options for the asset being borrowed.

  • broadcast: true to broadcast the transaction on the network

The signed transaction borrowing the asset

cancel_order

Cancel an existing order.

  • order_id: the id of order to be cancelled

  • broadcast: true to broadcast the transaction on the network

The signed transaction canceling the order

settle_asset

Schedules a market-issued asset for automatic settlement.

Holders of market-issued assets may request a forced settlement for some amount of their asset. This means that the specified sum will be locked by the chain and held for the settlement period, after which time the chain will choose a margin position holder and buy the settled asset using the margin’s collateral.

The price of this sale will be based on the feed price for the market-issued asset being settled. The exact settlement price will be the feed price at the time of settlement with an offset in favor of the margin position, where the offset is a blockchain parameter set in the global_property_object.

  • account_to_settle: the name or id of the account owning the asset

  • amount_to_settle: the amount of the named asset to schedule for settlement

  • symbol: the name or id of the asset to settle

  • broadcast: true to broadcast the transaction on the network

The signed transaction settling the named asset.

get_market_history

Get OHLCV (Open, High, Low, Close, & Volume) data of a trading pair in a time range.

  • symbol: name or ID of the base asset

  • symbol2: name or ID of the quote asset

  • bucket: length of each time bucket in seconds.

  • start: the start of a time range, E.G. “2018-01-01T00:00:00”

  • end: the end of the time range

A list of OHLCV data, in “least recent first” order.

get_limit_orders

Get limit orders in a given market.

  • a: symbol or ID of asset being sold

  • b: symbol or ID of asset being purchased

  • limit: Maximum number of orders to retrieve

The limit orders, ordered from least price to greatest.

get_call_orders

Get call orders (aka margin positions) for a given asset.

  • a: symbol name or ID of the debt asset

  • limit: Maximum number of orders to retrieve

The call orders, ordered from earliest to be called to latest

get_settle_orders

Get forced settlement orders in a given asset.

  • a: Symbol or ID of asset being settled

  • limit: Maximum number of orders to retrieve

The settle orders, ordered from earliest settlement date to latest

generic-sidechain-listener-hld

Objective

This document is intended to outline generic design of a blockchain listener, a component used for monitoring changes on a target blockchain.

Assumptions

  • Blockchain node provides interface for monitoring changes in a blockchain.

  • Monitoring is based on new block, new transaction or filtered single event (like transfer operation to specific address).

  • There is a sufficient C/C++ library for connecting to monitoring interface.

Description

Implementing blockchain listener is highly blockchain specific task. There are no standardised interface that all blockchain nodes use for monitoring changes. We need to investigate target blockchain, get familiar with its way of monitoring changes, available protocols, libraries, etc…

The goal of processing data provided by listener is to find event of interest, in particular, a transfer operation to a target address (e.g. address of Peerplays primary wallet).

In order to be able to do this, we can put in place some common rules each listener needs to follow, in order to report usable data to event handler.

  • Listener needs to provide information about event of interest in a way that will enable event handler to narrow its processing to minimum.

  • Event handler, when processing event data provided by listener, must be able to get at least following information:

    • Sidechain transaction unique identifier

    • Transfer operation’s source address

    • Transfer operation’s target address

    • Transfer amount

    • Transaction fee (for transfer operation)

  • From what we know so far, listener can report new block, a transaction, or filtered single event (like specific operation involving specific address).

    • If new block is reported, we can go through block content, and look for events of interest, like specific operation involving specific address

    • If new transaction is reported, we can investigate what kind of operation it contains, and which addresses are involved

    • If listener supports filtered events, we can create a filter in a way that will report only event of interest

Block Diagram

Link to file:

Sequence diagram

Link to file

Sequence diagram shows sidechain listener interactions with the rest of the sidechain components.

Suggested implementation

As the implementing blockchain listener is highly blockchain specific task, we will not put any constraints on a listener implementation or require specific interface. Listener should be implemented any way it works, and sidechain handler task is to process input from event, use communication interface, if needed, to get the minimum required information about transfer, and pass it to higher level of processing.

User account ID

Network

Addreses

1.1.1

network::bitcoin

BitcoinAddress1

1.1.1

network::ethereum

EthereumAddress1

1.1.2

network::bitcoin

BitcoinAddress2

1.1.3

network::bitcoin

BitcoinAddress3

1.1.4

network::ethereum

EthereumAddress4

signed_transaction graphene::wallet::wallet_api::sell_asset(
    string seller_account, 
    string amount_to_sell, 
    string symbol_to_sell, 
    string min_to_receive, 
    string symbol_to_receive, 
    uint32_t timeout_sec = 0, 
    bool fill_or_kill = false, 
    bool broadcast = false)
signed_transaction graphene::
wallet
::
wallet_api
::borrow_asset(string borrower_name, string amount_to_borrow, string asset_symbol, string amount_of_collateral, bool broadcast = false)
signed_transaction graphene::wallet::wallet_api::cancel_order(
    object_id_type order_id, 
    bool broadcast = false)
signed_transaction graphene::wallet::wallet_api::settle_asset(
    string account_to_settle, 
    string amount_to_settle, 
    string symbol, 
    bool broadcast = false)
vector<bucket_object> graphene::wallet::wallet_api::get_market_history(
    string symbol, 
    string symbol2, 
    uint32_t bucket, 
    fc::time_point_sec start, 
    fc::time_point_sec end)const
vector<limit_order_object> graphene::wallet::wallet_api::get_limit_orders(
    string a, 
    string b, 
    uint32_t limit)const
vector<call_order_object> graphene::wallet::wallet_api::get_call_orders(
    string a, 
    uint32_t limit)const
vector<force_settlement_object> graphene::wallet::wallet_api::get_settle_orders(
    string a, 
    uint32_t limit)const
sell_asset()
draw.io
https://drive.google.com/file/d/1ErmQfeaWa9m67si4hb0RZs54WVYWR0pC/view?usp=sharing
draw.io
https://drive.google.com/file/d/17kbez7C1Djaj-2AgyEzQ1Z-5CrSZ5wZE/view?usp=sharing

Calculating Costs

1. Transaction Fee Considerations

Every operation on the Peerplays blockchain requires a small fee to cover the cost of the use of the network and data storage on the chain. These fees can add up so it's best to plan ahead, especially if you'll need to make hundreds or thousands of transactions.

The fees are set individually for every operation. The fees will also change over time due to blockchain governance voting. You can check the current fees using the get_global_properties function, and then calculate your total costs given how many times you'll need to run each operation.

You might do something like the following:

  1. Use the get_global_properties function. Copy the whole list of operation IDs/fees from the return.

  2. Download the latest copy of the Operation ID mapping.

  3. Combine the two lists to get the fee for each operation.

Then you can use your combined list to easily calculate the total transaction costs for what you plan to do. At this time, there is no automated process for generating such a list.

The PPY asset has a precision of 5. So the numbers listed in the get_global_properties function are in Satoshi. That is to say, to convert this number to nominal units, a decimal point is added 5 places from the right.

Some examples:

  • "fee": 1000 is really 0.01 PPY.

  • "premium_fee": 250000 is really 2.5 PPY.

  • "membership_lifetime_fee": 500000 is really 5 PPY.

1.1. get_global_properties

This function returns the blockchain’s slowly-changing settings (like the fees for each operation).

This object contains all of the properties of the blockchain that are fixed or that change only once per maintenance interval (daily) such as the current list of witnesses, committee_members, block interval, etc.

return type, namespace, & method
global_property_object graphene::wallet::wallet_api::get_global_properties()const

Calling this function is simple:

In the cli_wallet...
get_global_properties

The global_property_object is returned:

get_global_properties
{
  "id": "2.0.0",
  "parameters": {
    "current_fees": {
      "parameters": [[
          0,{
            "fee": 1000,
            "price_per_kbyte": 1000
          }
        ],[
          1,{
            "fee": 50
          }
        ],[
          2,{
            "fee": 0
          }
        ],[
          3,{
            "fee": "500000000000"
          }
        ],[
          4,{}
        ],[
          5,{
            "basic_fee": 500,
            "premium_fee": 250000,
            "price_per_kbyte": 1000
          }
        ],[
          6,{
            "fee": 100,
            "price_per_kbyte": 1000
          }
        ],[
          7,{
            "fee": 1000
          }
        ],[
          8,{
            "membership_annual_fee": "500000000000",
            "membership_lifetime_fee": 500000
          }
        ]
		# ... #
      ],
      "scale": 10000
    },
    "block_interval": 3,
    "maintenance_interval": 3600,
    "maintenance_skip_slots": 3,
    "committee_proposal_review_period": 3600,
    "maximum_transaction_size": 99999,
    # ... #
    "extensions": {
      "betting_rake_fee_percentage": 100,
      "live_betting_delay_time": 0,
      "sweeps_distribution_percentage": 200,
      # ... #
    }
  },
  "next_available_vote_id": 118,
  "active_committee_members": [
    # ... #
  ],
  "active_witnesses": [
    # ... #
  ],
  "active_sons": [{
      # ... #
    }
  ]
}

Parts of the example return have been truncated to fit. The actual return is much longer.

1.2. An Example

Let's say you need to make 50,000 NFTs with custom permissions and issue them to various accounts.

To calculate the total cost for this, you'll find the transaction fees for each transaction to accomplish the goal and then multiply by how may times you need to execute each transaction.

Using get_global_properties and the list of operation ID's you find the following transaction fees:

  1. Operation #85 -> custom_account_authority_create_operation -> Fee = 0.005 PPY & Kb of Data = 0.01 PPY

  2. Operation #92 -> nft_metadata_create_operation -> Fee = 0.1 PPY & Kb of Data = 0.01 PPY

  3. Operation #94 -> nft_mint_operation -> Fee = 0.01 PPY & Kb of Data = 0.01 PPY

You will need to create the custom permissions once: 0.005 PPY (the fee) + 0.01 PPY (for 1 Kb worth of data). Then you will need to create the NFT metadata once: 0.1 PPY (the fee) + 0.01 PPY (for 1 Kb worth of data). Last you will need to mint the 50,000 NFTs, which issues them to the accounts that will ultimately own them: 500 PPY (the fee) + 500 PPY (for 1 Kb worth of data).

A Kb (Kilobyte) of data can accommodate about 1/2 page worth of text. So unless you have a lot of information to apply to your NFTs, the 0.01 PPY for a Kb of data should cover most use cases!

When added all together, you get:

0.005 + 0.01 + 0.1 + 0.01 + 500 + 500 = 1,000.125 PPY cost in transaction fees to accomplish your goal. And this accounts for the use of an entire Kb of data per NFT. Using less data will make the total much less in this case.

This could represent 50,000 movie tickets, 50,000 shares of a company, or even 50,000 college degrees!

Remember the 5 "P's"... Proper planning prevents poor performance!

Authentication with PeerID

1. Introduction

This guide describes how to use PeerID to enable your application to perform operations on behalf of a Peerplays account. The preferred method of authentication is OAuth. We use parts of the OAuth 2.0 protocol.

PeerID also allows your users to register and login to their Peerplays accounts using their Facebook, Google, and Discord accounts. PeerID uses their respective authentication to verify the user and log them into their Peerplays account.

PeerID doesn’t store passwords or keys anywhere. It uses the custom permissions on the Peerplays blockchain to perform the operations on behalf of the user.

Authentication involves:

  1. Registering your app to obtain a client ID and client secret. This includes specifying scopes (permissions) your app requires.

  2. Getting an access token for the PeerID user. This includes the user authorizing your app using their login credentials.

  3. Sending the token in your API request to perform an operation on the Peerplays blockchain on behalf of the user.

2. Registration

To make an application that uses the PeerID API, you first need to register your application on the PeerID site. When creating your app, enter your domains, to which your users are redirected after being authorized. You can provide several domains, for example, if you wish to use the same client for different environments.

Once you create a developer application, you are assigned a client ID. Some authentication flows also require a client secret, which you can view on the same page as the client ID.

  • Client IDs are public and can be shared (for example, embedded in the source of a Web page).

  • Client secrets are equivalent to a password for your application and must be kept confidential.

Never expose the client secret to users, even in an obscured form!

3. Getting Tokens

PeerID supports several authentication flows: 1. OAuth Authorization code flow: This should be used when your application uses a client-server architecture, can securely store a client secret, can request the user to allow the app to perform some operations on behalf of the user, and can make server-to-server requests. This is the recommended approach. 2. OAuth Resource Owner Password Credentials flow: This should be used when your application is a single page browser app using a client-server architecture and can ask the client for credentials but you don't want the client to divert from your page.

The client credentials should never be stored in your database.

OAuth Authorization code flow Follow the below steps to get the access token for the user using the OAuth Authorization code flow:

  1. Send the user you want to authenticate to your registered redirect URI. An authorization page will ask the user to sign up or log into PeerID and allow the user to choose whether to authorize your application/identity system.

Create a <a href="">login</a>:

GET https://peerid.peerplays.download/permissions  
?client_id=<your client ID>  
&redirect_uri=<URI with your registered domain>

You can also pass an optional state parameter of string type. This can be a unique token generated by your application. This is an OAuth 2.0 opaque value, used to avoid CSRF attacks. This value is echoed back in the response. We strongly recommend you use this.

  1. If the user authorizes your application, the user is redirected to your redirect URL:

https://<your registered redirect URI>/?code=<authorization code>

The OAuth 2.0 authorization code is a randomly generated string. It is used in the next step, a request made to the token endpoint in exchange for an access token.

The response includes the state parameter, if it was in your request.

  1. On your server, get an access token by making this request:

POST https://peerid.peerplays.download/api/v1/auth/exchange  
?code=<authorization code received in previous step>  
&client_id=<your client ID>  
&client_secret=<your client secret>
  1. We respond with a json-encoded access token. The response looks like this:

{  
    "result": {  
        "expires": "<expiry date of the token>",  
        "app_id": <your client ID>,  
        "scope": <permissions granted by the user>,  
        "token": "<access token for the user>",  
        "refresh_token": "<refresh token for the user>"  
    },  
    "status": 200  
}

Store the access token and refresh token like passwords.

OAuth Resource Owner Password Credentials flow Follow the below steps to get the access token using the OAuth Resource Owner Password Credentials flow:

  1. In your app, request for user's login credentials (i.e. username or email ID and mobile or password) and on your server, get an access token by making this request:

POST https://peerid.peerplays.download/api/v1/auth/token  
?login=<user's username or email ID>  
&password=<user's password>  
&mobile=<user's mobile number>  
&client_id=<your client ID>

Either password or mobile parameters has to be passed in this request. If both are passed, the PeerID server validates both of them along with the login.

  1. We respond with a json-encoded access token. The response looks like this:

{  
    "result": {  
        "expires": "<expiry date of the token>",  
        "app_id": <your client ID>,  
        "scope": <permissions granted by the user>,  
        "token": "<access token for the user>",  
        "refresh_token": "<refresh token for the user>"  
    },  
    "status": 200  
}

Store the access token and refresh token like passwords.

4. Sending Access Tokens

Once you have the user’s access token, your app can perform the permitted operations on behalf of the user on the Peerplays blockchain using the /api/v1/app/operations API. You have to pass the access token for the user in the Authorization header for this API like:

curl -H "Authorization: Bearer <access token>" https://peerid.peerplays.download/api/v1/app/operations

The access token for one app cannot be used for another app.

5. Refreshing Access Tokens

New OAuth2 access tokens expire. Token-expiration periods vary in length, based on how and when the token was acquired. Tokens return an expires field indicating how long the token should last. However, you should build your applications in such a way that they are resilient to token authentication failures. In other words, an application capable of refreshing tokens should not need to know how long a token will live. Rather, it should be prepared to deal with the token becoming invalid at any time.

On seeing a 401 - Unauthorized error, an application should try to refresh the session if a refresh token is present. If the refresh fails, the application should re-prompt the end user with another authentication dialog via the standard OAuth 2.0 flow.

Generally, refresh tokens are used to extend the lifetime of a given authorization.

How to refresh a token:

To refresh a token, you need the refresh_token that you get in the response when you exchange your code for token and the client ID and client secret. The following API returns the new access token:

POST https://peerid.peerplays.download/api/v1/auth/refreshtoken  
?refresh_token=<refresh token for the user>  
&client_id=<your client ID>  
&client_secret=<your client secret>

The response will look like this:

{  
    "result": {  
        "expires": "<expiry date of the token>",  
        "app_id": <your client ID>,  
        "scope": <permissions granted by the user>,  
        "token": "<access token for the user>",  
        "refresh_token": "<refresh token for the user>"  
    },  
    "status": 200  
}

Once again, store the access token and refresh token like you would a password.

6. Glossary

OAuth (OAuth 2.0) - Open Authorization - An open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords.

CSRF Attacks - Cross-Site Request Forgery - A type of malicious exploit of a website where unauthorized commands are submitted from a user that the web application trusts.

SON rewards

1. Purpose

The purpose of this document is to outline the steps required to pay the SONs for their contribution to the Peerplays network.

2. Scope

The functional requirement listed in this document will be limited to the payment portion of the SON. This will outline the required steps to pay the SONs for the functions performed by them on the Peerplays blockchain. Also outlined here will be the sequence in which the required steps will be performed including:

  • any interactions with the user.

  • validations to ensure complete and accurate information gathering.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of SONs. As per the current implementation of Sidechain, a multisig bitcoin wallet will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multisig bitcoin wallet and will be required to sign any withdrawal transaction. When a SONs changes, the transaction signing key of the outgoing witness needs to be removed from the multisig bitcoin wallet and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SONs will be independent of the witnesses and don't need to be changed much often.

4. Process Overview

Described here is the process to pay the SONs on the Peerplays Blockchain.

5. Flow Diagram

N/A

6. Context

The SON operators will be paid in PPY from the payment pool set up specifically for payments to SONs. This pool will be replenished by depositing a percentage of all the transaction on the Peerplays network. This percentage should be a chain parameter so that it can be changed. The fee will be distributed at the Maintenance intervals based on transactions signed and weight of voting (therefore voting power affects payout) for each SON. Currently set maximum SON payment is 200 PPY daily and is specified in `SONS_DAILY_MAX_REWARD`.

7. Requirements

7.1 Supported Operation Types

All operations performed by SONs must be tallied and paid according to budget and defined payout procedure (as described in sections below).

System must include a library (global parameters) of configurable fee amounts fee amounts associated with each operation. Library must track each operation, its type, fee amount and currency in which fee is charged (PPY by default). Fees are set and amendable by committee members in accordance with committee member procedures to update global parameters.

Operations commonly performed by SONs are as follows:

  • asset_issue_operation

  • asset_reserve_operation

  • proposal_create_operation

  • proposal_update_operation

  • proposal_delete_operation

  • son_create_operation

  • son_update_operation

  • son_delete_operation

  • son_heartbeat_operation

  • son_report_down_operation

  • son_maintenance_operation

  • son_wallet_recreate_operation

  • son_wallet_update_operation

  • son_wallet_deposit_create_operation

  • son_wallet_deposit_process_operation

  • son_wallet_withdraw_create_operation

  • son_wallet_withdraw_process_operation

See Risks section for considerations regarding fee amounts and their implications on financial viability of SON.

7.2 Paying Witnesses

Whenever a witness generates a new block, reward amount must be immediately deposited into witness account's vesting balance.

The amount must be withdrawn from witness_budget

7.3 Collecting Fees

All operations require a fee to be collected and paid to the network.

Fee collection is determined by operation type (as described in section Supported Operation Types):

  1. Core asset transaction fees are deducted from payer's account

  2. UIA (pBTC) transaction fees are converted to core asset using base exchange rate (note: bBTC to BTC is 1:1)fee mus

In a scenario where user has 0 PPY, fee must be collected from fee_pool.

7.4 Calculating budget

The equation for calculating SON budget is as follows:

current_supply = current_supply + (required_witness_budget + required_worker_budget + required_son_budget - leftover_worker_funds - core_accumulated_fee - leftover_witness_budget - leftover_son_budget)

reserve_supply = max_supply - current_supply

  • required_witness_budget - required witness budget till next maintenance interval

  • required_worker_budget - required worker budget till next maintenance interval

  • required_son_budget - reserved SON budget to be paid out in the next maintenance interval = (chain_parameters.son_pay_max)

  • leftover_worker_funds - Remaining funds from previous worker payout

  • core_accumulated_fee - Accumulated fee (after all the cuts removed from it), since the last maintenance interval.

  • leftover_witness_budget - Leftover funds from previous witness budget ( happens if any block is missed in between )

  • leftover_son_budget - Leftover funds from previous son budget ( happens if there are no SON transactions on the network )

other required variables:

  • total_transactions_per_day - tracks number of transactions SON participated in

  • SONs_REWARD_POOL - stores SON reward amounts

  • SONS_DAILY_MAX_REWARD - configurable variable which sets maximum size of reward

  • son_pay_max - dictates how much SONs are to be paid out it next payment interval

7.5 Determining payout

Payout must be determined by the number of transactions verified by a node. Higher availability nodes participate in more transactions and therefore receive higher payout.

SONs are paid based on % ratio between total_transactions_per_day and SONS_DAILY_MAX_REWARD, where SON's % share of daily transactions determines what % of SONS_DAILY_MAX_REWARD is paid. Payout happens only during SON maintenance interval, therefore payout is configurable based on the payment interval and can be configured to happen once every x maintenance intervals.

7.6 Payment Pool

Payments to SONs are stored inside son_budget which functions similarly to witness_budget. Specifically, son_budget accumulates transaction fees collected by peerplays network. As described above, payout happens during the maintenance interval .

SONS_DAILY_MAX_REWARD must initially be set to 200 PPY. We may to have to change this as per market realities etc. Currently BTC is the only supported cryptocurrency.

Note: SONS_DAILY_MAX_REWARD must be reviewed in production to determine whether this limit is too low or restrictive. Depending on the fees associated with each transaction (as described in Transaction Type section above), highly active SONs may perform a number of operations and reach daily max limit quickly thus creation a disproportion between operations performed vs max daily reward.

8 Risks

SON concept has proven to be technically feasible, however, there are financial viability implications that must be taken into account.

SON operations must be priced in ways that offset electricity cost of node operators by a margin that makes it worthwhile to operate a node, however also low enough to make the blockchain cost effective to its users.

Inability to find a fee model attractive to node operators will impede availability of SONs (for which there is a minimum threshold), while high fees are likely to impede user interest due to high cost.

Note that because fees may be amended by committee members, fees they set may create risks mentioned above. It is recommended that committee member operations in relation to fees are closely monitored.

Sample test:

  1. configure witness_pay_per_block chain parameter = 1

  2. configure son_pay_daily_max chain extension parameter = 10000 ( As we don’t have enough fee collected on our chain, keeping it low is essential to test properly)

  3. configure son_pay_time chain extension parameter = maintenance_interval or multiples of maintenance_interval. (Eg. x, 2x, 3x, 4x etc x = maintenance_interval). As budget is calculated during maintenance period son_pay_time should be multiples of maintenance_interval.

  4. Temporarily, txs_signed of son_statistics_object is incremented through son heartbeats to enable testing of SON Rewards. ( txs_signed can be obtained by get_object 2.24.0 command). txs_signed are reset and added to total_txs_signed if SONs are paid out successfully.

  5. Check that the get_dynamic_global_properties has son_budget and last_son_payout_time updated correctly like below,

    get_dynamic_global_properties { "id": "2.1.0", "random": "0f0b35fba1f53d22384e642356c25510e63f18b7", "head_block_number": 4708, "head_block_id": "00001264be90f462d553e2edee2e7fee698215c1", "time": "2020-03-19T10:25:42", "current_witness": "1.6.2", "next_maintenance_time": "2020-03-19T10:30:00", "last_budget_time": "2020-03-19T10:24:00", "witness_budget": 93, "last_son_payout_time": "2020-03-19T10:24:00", "son_budget": 10000, "accounts_registered_this_interval": 0, "recently_missed_count": 7, "current_aslot": 8917831, "recent_slots_filled": "1298074214633706907132624082304903", "dynamic_flags": 0, "last_irreversible_block_num": 4700 }

  6. list_account_balances <sonaccount01> to check that the pay is added to the SON account’s balance.

  7. If there are 13 active SONs, and each SON sent 3 heartbeats before next payout time, You can find below snippet in the log during the chain maintenance, pay 769 to 2.24.0 for 3 transactions signed total txs = 13 x 3 = 39. so pay for each SON -> (3/39)x10000 = 769

Peerplays Development FAQs

Bitcoin-SON

❓ How can I generate Bitcoin addresses?

Command:

./bitcoin-cli -rpcuser=1 -rpcpassword=1 -rpcwallet=default getnewaddress

References:

❓ How to get TEST BTC on the REGTEST network?

From developer.bitcoin.org...

For situations where interaction with random peers and blocks is unnecessary or unwanted, Bitcoin Core’s regression test mode (regtest mode) lets you instantly create a brand-new private block chain with the same basic rules as testnet—but one major difference: you choose when to create new blocks, so you have complete control over the environment.

Many developers consider regtest mode the preferred way to develop new applications. The following example will let you create a regtest environment after you first configure bitcoind.

bitcoind -regtest -daemon

Start bitcoind in regtest mode to create a private block chain.

bitcoin-cli -regtest generatetoaddress 101 $(bitcoin-cli -regtest getnewaddress)

Generate 101 blocks using a special RPC which is only available in regtest mode. This takes less than a second on a generic PC. Because this is a new block chain using Bitcoin’s default rules, the first blocks pay a block reward of 50 bitcoins. Unlike mainnet, in regtest mode only the first 150 blocks pay a reward of 50 bitcoins. However, a block must have 100 confirmations before that reward can be spent, so we generate 101 blocks to get access to the coinbase transaction from block #1.

bitcoin-cli -regtest getbalance

Verify that we now have 50 bitcoins available to spend.

You can now use Bitcoin Core RPCs prefixed with bitcoin-cli -regtest.

Regtest wallets and block chain state (chainstate) are saved in the regtest subdirectory of the Bitcoin Core configuration directory. You can safely delete the regtest subdirectory and restart Bitcoin Core to start a new regtest. (See the Developer Examples Introduction for default configuration directory locations on various operating systems. Always back up mainnet wallets before performing dangerous operations such as deleting.)

Reference:

❓ How can I generate / find the public key for a Bitcoin address?

Command:

./bitcoin-cli -rpcuser=1 -rpcpassword=1 -rpcwallet=default getaddressinfo "address"

References:

❓ If funds are deposited to a Bitcoin address, will there be logs?

❓ What is the cli_command to generate a Bitcoin deposit address in the Peerplays blockchain?

Command Definition:

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::add_sidechain_address(
    string account,
    sidechain_type sidechain,
    string deposit_public_key,
    string withdraw_public_key,
    string withdraw_address,
    bool broadcast);

Command Structure:

add_sidechain_address <account> <sidechain> <deposit_public_key> <withdraw_public_key> <withdraw_address> true

Command Example:

add_sidechain_address myaccount123 bitcoin 03c8d1c33727788ca1f61e13bdeca0127047527a0880c816056b4015d6e2d36c1e 025cee805793fd94ca1933cc28ef9c065addd0e256195f1a541be0cd21867ac1c5 1EToWbQDvEwwie6jYsuM7WkZnh7rCn5Ecu true

Reference:

❓ If a Bitcoin deposit address is created for a Peerplays address (account) what are the logs in the Peerplays blockchain?

❓ How to run a Peerplays blockchain node with RPC debugging turned on?

Gamified Proof of Stake (GPOS)

❓ What are the blockchain logs when a successful GPOS Vesting is done?

Faucet

❓ What are the logs in faucet when an account is successfully created?

One can use Curl command or POSTMAN in order to create a new account in the Faucet. With Curl you can do the following:

curl -X POST http://<IP_ADDRESS>:<PORT_NUMBER>/api/v1/accounts 
-H 'content-type: application/json' 
-d '{
	"account": {
		"name": "<ACCOUNT_NAME>",
		"owner_key": "TEST5WaszCsqVN9hDkXZPMyiUib3dyrEA4yd5kSMgu28Wz47B3wUqa",
		"active_key": "TEST5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE",
		"memo_key": "TEST5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE"
	}
}'

IP_ADDRESS should be 127.0.0.1 or localhost when running it directly in a VM or on your local machine.

owner_key, active_key, memo_key should start with TEST on testnet, and it should be PPY on mainnet.

If the result of the above is successful, there should be output like this:

{
	"account": {
		"active_key": "TEST5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE",
		"memo_key": "TEST5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE",
		"name": "account-name4",
		"owner_key": "TEST5WaszCsqVN9hDkXZPMyiUib3dyrEA4yd5kSMgu28Wz47B3wUqa",
		"referrer": "nathan"
	}
}

And in case of any error, it will be following (i.e. duplicate account):

{"error":{"base":["Account exists"]}}

You can also track the logs in Faucet container, with the following command:

docker logs --follow <Faucet-Container-ID>
For example: docker logs --follow 47c101add138

And look for logs when receiving Create Account requests, with 200 status code as a result.

37.252.95.183 - - [06/Oct/2021 17:55:29] "OPTIONS /api/v1/accounts HTTP/1.1" 200 -
37.252.95.183 - - [06/Oct/2021 17:55:30] "POST /api/v1/accounts HTTP/1.1" 200 -

Peerplays DEX

❓ How do I setup a local DEX UI project?

This works with a Faucet and a local QA environment (create account & login).

First, pull the DEX repository from here.

After setting up the project, update the following variables in .env file:

FAUCET_URL='http://<IP_ADDRESS>:5000/api/v1/accounts'
BLOCKCHAIN_ENDPOINTS='ws://<IP_ADDRESS>:8090/api'

IP_ADDRESS should be 127.0.0.1 or localhost when running it directly on your local machine.

Peerplays QA Environment

❓ How do I transfer funds between accounts in a Peerplays QA Environment network?

In the QA environment setup by instructions in here, execute commands in Peerplays01 container with the following:

docker exec -it peerplaysqaenvironment_peerplays01_1 /bin/bash

Then running into account’s wallet:

./cli_wallet list_account_balances <ACCOUNT_NAME>
For example: ./cli_wallet list_account_balances armin

Unlock the wallet with the default password (which is "password"):

unlock password

Get the private key for active key (public key):

get_private_key_from_password "<ACCOUNT_NAME>" active "<ACCOUNT_PASSWORD>"

ACCOUNT_PASSWORD is the password defined when creating account in DEX UI.

Import the private key returned from previous step:

import_key <ACCOUNT_NAME> <PRIVATE_KEY>
For example:
import_key armin 5JckQ6g57P9YyyumHCRj1cNbHTiMEUVA2HjVDJqXDDPYizEaAMu

Finally transfer with the following:

transfer <FROM_ACCOUNT_NAME> <TO_ACCOUNT_NAME> <AMOUNT> TEST "" true 
For example: transfer armin nathan 10 TEST "" true

memo key should be empty string for it to work. With list_core_accounts command you can check all account’s balances.

❓How to ensure QA environment is healthy ?

If you are getting "Generated block..." and "Scheduled SON..." messages, and SON last active timestamps are updated regularly, SON network is working as expected. To get last active timestamp, first use get_object 1.33.X (ids are 1.33.0, 1.33.1, ... 1.33.6), statistic object id will be there, and then use get_object statistic_object_id (I believe ids are 2.25.0, 2.25.1, ... 2.25.6). All timestamps should be in a last few minutes.

Transaction Builder

Transaction Builder

begin_builder_transaction

Create a new transaction builder.

Handle of the new transaction builder.

add_operation_to_builder_transaction

Append a new operation to a transaction builder.

  • transaction_handle: handle of the transaction builder

  • op: the operation in JSON format

replace_operation_in_builder_transaction

Replace an operation in a transaction builder with a new operation.

  • handle: handle of the transaction builder

  • operation_index: the index of the old operation in the builder to be replaced

  • new_op: the new operation in JSON format

set_fees_on_builder_transaction

Calculate and update fees for the operations in a transaction builder.

  • handle: handle of the transaction builder

  • fee_asset: name or ID of an asset that to be used to pay fees

Total fees.

preview_builder_transaction

Show content of a transaction builder.

  • handle: handle of the transaction builder

A transaction.

sign_builder_transaction

Sign the transaction in a transaction builder and optionally broadcast to the network.

  • transaction_handle: handle of the transaction builder

  • broadcast: whether to broadcast the signed transaction to the network

A signed transaction.

propose_builder_transaction

Create a proposal containing the operations in a transaction builder (create a new proposal_create operation, then replace the transaction builder with the new operation), then sign the transaction and optionally broadcast to the network.

Note: this command is not effective because you're unable to specify a proposer. It will be deprecated in a future release. Use instead.

  • handle: handle of the transaction builder

  • expiration: when the proposal will expire

  • review_period_seconds: review period of the proposal in seconds

  • broadcast: whether to broadcast the signed transaction to the network

A signed transaction.

propose_builder_transaction2

Create a proposal containing the operations in a transaction builder (create a new proposal_create operation, then replace the transaction builder with the new operation), then sign the transaction and optionally broadcast to the network.

  • handle: handle of the transaction builder

  • account_name_or_id: name or ID of the account who would pay fees for creating the proposal

  • expiration: when the proposal will expire

  • review_period_seconds: review period of the proposal in seconds

  • broadcast: whether to broadcast the signed transaction to the network

A signed transaction.

remove_builder_transaction

Destroy a transaction builder.

  • handle: handle of the transaction builder

serialize_transaction

Converts a signed_transaction in JSON form to its binary representation.

  • tx: the transaction to serialize

The binary form of the transaction. It will not be hex encoded, this returns a raw string that may have null characters embedded in it

sign_transaction

Signs a transaction.

Given a fully-formed transaction that is only lacking signatures, this signs the transaction with the necessary keys and optionally broadcasts the transaction.

  • tx: the unsigned transaction

  • broadcast: true if you wish to broadcast the transaction

The signed version of the transaction

get_prototype_operation

Returns an uninitialized object representing a given blockchain operation.

This returns a default-initialized object of the given type; it can be used during early development of the wallet when we don’t yet have custom commands for creating all of the operations the blockchain supports.

Any operation the blockchain supports can be created using the transaction builder’s , but to do that from the CLI you need to know what the JSON form of the operation looks like. This will give you a template you can fill in. It’s better than nothing.

  • operation_type: the type of operation to return, must be one of the operations defined in graphene/protocol/operations.hpp (e.g., “global_parameters_update_operation”)

A default-constructed operation of the given type.

transaction_handle_typegraphene::wallet::wallet_api::begin_builder_transaction()
void graphene::wallet::wallet_api::add_operation_to_builder_transaction(
    transaction_handle_typetransaction_handle, 
    const operation &op)
void graphene::wallet::wallet_api::replace_operation_in_builder_transaction(
    transaction_handle_typehandle, 
    unsigned operation_index, 
    const operation &new_op)
asset graphene::wallet::wallet_api::set_fees_on_builder_transaction(
    transaction_handle_typehandle, 
    string fee_asset = GRAPHENE_SYMBOL)
transaction graphene::wallet::wallet_api::preview_builder_transaction(
    transaction_handle_typehandle)
signed_transaction graphene::wallet::wallet_api::sign_builder_transaction(
    transaction_handle_typetransaction_handle, 
    bool broadcast = true)
signed_transaction graphene::wallet::wallet_api::propose_builder_transaction(
    transaction_handle_typehandle, 
    time_point_sec expiration = time_point::now() + fc::minutes(1), 
    uint32_t review_period_seconds = 0, 
    bool broadcast = true)
signed_transaction graphene::wallet::wallet_api::propose_builder_transaction2(
    transaction_handle_typehandle, 
    string account_name_or_id, 
    time_point_sec expiration = time_point::now() + fc::minutes(1), 
    uint32_t review_period_seconds = 0, 
    bool broadcast = true)
void graphene::wallet::wallet_api::remove_builder_transaction(
    transaction_handle_typehandle)
string graphene::wallet::wallet_api::serialize_transaction(
    signed_transaction tx)const
signed_transaction graphene::wallet::wallet_api::sign_transaction(
    signed_transaction tx, 
    bool broadcast = false)
operation graphene::wallet::wallet_api::get_prototype_operation(
    string operation_type)
propose_builder_transaction2()
add_operation_to_builder_transaction()
PBSA / PeerID / PeerID-backendGitLab

Account Calls

Account Calls

list_my_accounts

Lists all accounts controlled by this wallet. This returns a list of the full account objects for all accounts whose private keys we possess.

vector<account_object> graphene::wallet::wallet_api::list_my_accounts()

A list of account objects

list_accounts

Lists all accounts registered in the blockchain. This returns a list of all account names and their account ids, sorted by account name.

Use the lowerbound and limit parameters to page through the list. To retrieve all accounts, start by setting lowerbound to the empty string "", and then each iteration, pass the last account name returned as the lowerbound for the next list_accounts() call.

map<string, account_id_type> graphene::wallet::wallet_api::list_accounts(
    const string &lowerbound, 
    uint32_t limit)
  • lowerbound: the name of the first account to return. If the named account does not exist, the list will start at the account that comes after lowerbound

  • limit: the maximum number of accounts to return (max: 1000)

A list of accounts mapping account names to account ids.

list_account_balances

List the balances of an account. Each account can have multiple balances, one for each type of asset owned by that account. The returned list will only contain assets for which the account has a non-zero balance.

vector<asset> graphene::wallet::wallet_api::list_account_balances(
    const string &id)
  • id: the name or id of the account whose balances you want

A list of the given account’s balances

register_account

Registers a third party’s account on the blockchain.

This function is used to register an account for which you do not own the private keys. When acting as a registrar, an end user will generate their own private keys and send you the public keys. The registrar will use this function to register the account on behalf of the end user.

See also create_account_with_brain_key()****

signed_transaction graphene::wallet::wallet_api::register_account(
    string name, 
    public_key_type owner, 
    public_key_type active, 
    string registrar_account, 
    string referrer_account, 
    uint32_t referrer_percent, 
    bool broadcast = false)
  • name: the name of the account, must be unique on the blockchain. Shorter names are more expensive to register; the rules are still in flux, but in general names of more than 8 characters with at least one digit will be cheap.

  • owner: the owner key for the new account

  • active: the active key for the new account

  • registrar_account: the account which will pay the fee to register the user

  • referrer_account: the account who is acting as a referrer, and may receive a portion of the user’s transaction fees. This can be the same as the registrar_account if there is no referrer.

  • referrer_percent: the percentage (0 - 100) of the new user’s transaction fees not claimed by the blockchain that will be distributed to the referrer; the rest will be sent to the registrar. Will be multiplied by GRAPHENE_1_PERCENT when constructing the transaction.

  • broadcast: true to broadcast the transaction on the network

The signed transaction registering the account

upgrade_account

Upgrades an account to prime status. This makes the account holder a ‘lifetime member’.

signed_transaction graphene::wallet::wallet_api::upgrade_account(
    string name, 
    bool broadcast)
  • name: the name or id of the account to upgrade

  • broadcast: true to broadcast the transaction on the network

The signed transaction upgrading the account

create_account_with_brain_key

Creates a new account and registers it on the blockchain.

See also suggest_brain_key(), register_account()****

signed_transaction graphene::wallet::wallet_api::create_account_with_brain_key(
    string brain_key, 
    string account_name, 
    string registrar_account, 
    string referrer_account, 
    bool broadcast = false)
  • brain_key: the brain key used for generating the account’s private keys

  • account_name: the name of the account, must be unique on the blockchain. Shorter names are more expensive to register; the rules are still in flux, but in general names of more than 8 characters with at least one digit will be cheap.

  • registrar_account: the account which will pay the fee to register the user

  • referrer_account: the account who is acting as a referrer, and may receive a portion of the user’s transaction fees. This can be the same as the registrar_account if there is no referrer.

  • broadcast: true to broadcast the transaction on the network

The signed transaction registering the account

transfer

Transfer an amount from one account to another.

signed_transaction graphene::wallet::wallet_api::transfer(
    string from, 
    string to, 
    string amount, 
    string asset_symbol, 
    string memo, 
    bool broadcast = false)
  • from: the name or id of the account sending the funds

  • to: the name or id of the account receiving the funds

  • amount: the amount to send (in nominal units, for example to send half of a PPY specify 0.5)

  • asset_symbol: the symbol or id of the asset to send

  • memo: a memo to attach to the transaction. The memo will be encrypted in the transaction and readable for the receiver. There is no length limit other than the limit imposed by maximum transaction size, but transaction increase with transaction size

  • broadcast: true to broadcast the transaction on the network

The signed transaction transferring funds

transfer2

This method works just like transfer, except it always broadcasts and returns the transaction ID (hash) along with the signed transaction.

pair<transaction_id_type, signed_transaction> graphene::wallet::wallet_api::transfer2(
    string from, 
    string to, 
    string amount, 
    string asset_symbol, 
    string memo)
  • from: the name or id of the account sending the funds

  • to: the name or id of the account receiving the funds

  • amount: the amount to send (in nominal units, for example to send half of a PPY specify 0.5)

  • asset_symbol: the symbol or id of the asset to send

  • memo: a memo to attach to the transaction. The memo will be encrypted in the transaction and readable for the receiver. There is no length limit other than the limit imposed by maximum transaction size, but transaction increase with transaction size

The transaction ID (hash) along with the signed transaction transferring funds

whitelist_account

Whitelist and blacklist accounts, primarily for transacting in whitelisted assets.

Accounts can freely specify opinions about other accounts, in the form of either whitelisting or blacklisting them. This information is used in chain validation only to determine whether an account is authorized to transact in an asset type which enforces a whitelist, but third parties can use this information for other uses as well, as long as it does not conflict with the use of whitelisted assets.

An asset which enforces a whitelist specifies a list of accounts to maintain its whitelist, and a list of accounts to maintain its blacklist. In order for a given account A to hold and transact in a whitelisted asset S, A must be whitelisted by at least one of S’s whitelist_authorities and blacklisted by none of S’s blacklist_authorities. If A receives a balance of S, and is later removed from the whitelist(s) which allowed it to hold S, or added to any blacklist S specifies as authoritative, A’s balance of S will be frozen until A’s authorization is reinstated.

signed_transaction graphene::wallet::wallet_api::whitelist_account(
    string authorizing_account, 
    string account_to_list, 
    account_whitelist_operation::account_listing new_listing_status, 
    bool broadcast = false)
  • authorizing_account: the account who is doing the whitelisting

  • account_to_list: the account being whitelisted

  • new_listing_status: the new whitelisting status

  • broadcast: true to broadcast the transaction on the network

The signed transaction changing the whitelisting status

get_vesting_balances

Get information about a vesting balance object or vesting balance objects owned by an account.

vector<vesting_balance_object_with_info> graphene::wallet::wallet_api::get_vesting_balances(
    string account_name)
  • account_name: An account name, account ID, or vesting balance object ID.

A list of vesting balance objects with additional info

withdraw_vesting

Withdraw a vesting balance.

signed_transaction graphene::wallet::wallet_api::withdraw_vesting(
    string witness_name, 
    string amount, 
    string asset_symbol, 
    bool broadcast = false)
  • witness_name: The account name of the witness, also accepts account ID or vesting balance ID type.

  • amount: The amount to withdraw.

  • asset_symbol: The symbol of the asset to withdraw.

  • broadcast: true if you wish to broadcast the transaction

The signed transaction

get_account

Returns information about the given account.

account_object graphene::wallet::wallet_api::get_account(
    string account_name_or_id)const
  • account_name_or_id: the name or ID of the account to provide information about

The public account data stored in the blockchain

get_account_id

Lookup the id of a named account.

account_id_type graphene::wallet::wallet_api::get_account_id(
    string account_name_or_id)const
  • account_name_or_id: the name or ID of the account to look up

The id of the named account

get_account_history

Returns the most recent operations on the named account.

This returns a list of operation history objects, which describe activity on the account.

vector<operation_detail> graphene::wallet::wallet_api::get_account_history(
    string name, 
    int limit)const
  • name: the name or id of the account

  • limit: the number of entries to return (starting from the most recent)

A list of operation_history_objects

approve_proposal

Approve or disapprove a proposal.

signed_transaction graphene::wallet::wallet_api::approve_proposal(
    const string &fee_paying_account, 
    const string &proposal_id, 
    const approval_delta &delta, 
    bool broadcast)
  • fee_paying_account: The account paying the fee for the op.

  • proposal_id: The proposal to modify.

  • delta: Members contain approvals to create or remove. In JSON you can leave empty members undefined.

  • broadcast: true if you wish to broadcast the transaction

The signed version of the transaction

bitcoin-sidechain-multisig-bitcoin-wallet-and-bitcoin-addresses-pw

Bitcoin sidechain Multisig Bitcoin Wallet and Bitcoin addresses (PW)

This doc describes the design of the multisignature Bitcoin wallet - (Primary Wallet - hereinafter - PW) mechanism as related to SON implementation, and the operations and objects concerning it.

PW is used to store all the BTC that has been deposited by users. The signatures included in it are the signatures of the accounts that are active SONs (PeerPlays blockchain nodes with SON enabled and having enough vote weight to be included in Sidechain operations) - therefore all the BTC in PW is under the control of active SONs. No SON can control the BTC stored there by himself, therefore a degree of decentralization is required.

Multisignature (multisig) refers to requiring more than one key to authorize a Bitcoin transaction. It is generally used to divide up responsibility for possession of Bitcoin.

Standard transactions on the Bitcoin network could be called “single-signature transactions,” because transfers require only one signature — from the owner of the private key associated with the Bitcoin address. However, the Bitcoin network supports much more complicated transactions that require the signatures of multiple people before the funds can be transferred. These are often referred to as M-of-N transactions (where M is the number of signatures required for sending a transaction, and N is the number of signatures available in a wallet). The idea is that Bitcoin becomes “encumbered” by providing addresses of multiple parties, thus requiring cooperation of those parties in order to do anything with them. These parties can be people, institutions or programmed scripts.

In our case, it is not enough to require M-of-N signatures to approve a transaction, as each signature comes with its own weight. This weight is determined by the number of votes received when voting for SONs. This requirement further complicates the bitcoin script, we cannot use the built-in OP_CHECKMULTISIG operation, but have to check every signature separately and add up the corresponding weights.

The address of the PW is stored in btc_address_object.

btc_pw_prevout_object

This object is created when sending a transaction in Biotcoin network, and stores the information about PW vout. It is structured as follows:

Type

Name

Description

prev_out

vout

Information about the previous vout

sha256

hash_id

vout identificator

bool

confirmed

Flag that shows if the vout is confirmed

bool

used

Flag that shows if the vout has been used

It stores the information on a PW vout with all the funds in it.

This object is created on each transaction from PW sent on Bitcoin blockchain.

Since all the funds on a PW are stored in one vout, it is required to be able to spend the money from an unconfirmed vout. Due to this fact, it is required to store the chain of PW vouts, from the last confirmed vout to the current vout. Due to the limitations of Bitcoin protocol the chain of vouts can not exceed 25. The chain of vouts is stored in btc_pw_prevout_index. The index is represented as a chain of vouts from PW. After a Bitcoin transaction from PW gets N confirmations on Bitcoin blockchain, it is considered confirmed, therefore its vout becomes confirmed. The index is then updated, with the latest confirmed vout replacing the previous latest confirmed vout.

The standard value for the required number of confirmations is N=6, but many exchanges use N=3 for deposits. It is a trade-off between speed (how long the conversion takes) and safety. We would start with N=6, but as SONs are basically exchanges, we could change the requirement to only N=3 confirmations if desired.

SideChain Bitcoin address

Bitcoin addresses are used to allow users to deposit Bitcoin to PeerPlays sidechain.

There are two types of Bitcoin addresses in PeerPlays network:

  • PW-address - the storage of all BTC deposited by users (described above).

  • Deposit-address - address generated for each user and used for depositing BTC to PeerPlays, after which the deposited BTC is sent to PW.

Operation to create Bitcoin address

The operation is called btc_address_create_operation. Its evaluator class creates an object called btc_address_object, containing a Bitcoin address. An address is a custom mutisig script consisting of keys and weights (sum of votes for a SON) SON.

btc_address_create_operation

This operation creates an object that stores the deposit address for an account (btc_address_object).

It includes the following fields:

Type

Name

Description

asset

fee

The fee for executing the operation on PeerPlays blockchain

account_id_type

payer

Account that pays the fee for the operation

account_id_type

owner

Account to own the created address

btc_address_object

This object is created on execution of btc_address_create_operationand stores the information about the address on Bitcoin blockchain.

It contains the following fields:

Type

Name

Description

account_id_type

owner

Account that the Bitcioin deposit address belongs to

btc_multisig_segwit_address

address

Information on the Bitcoin address

uint64_t

count_invalid_pub_key

The number of invalid co-sginatory keys in the address

Active SONs are co-signatories for the funds stored on PW. Each SON has a public key on Bitcoin (secp256k1) and the weight of its signature.

This is executed on Bitcoin blockchain with the following script:

<pubkey1> OP_CHECKSIG

OP_IF

<voting_weight1>

OP_ELSE

0

OP_ENDIF

OP_SWAP

<pubkey2> OP_CHECKSIG

OP_IF

<voting_weight2>

OP_ADD

OP_ENDIF

...

OP_SWAP

<pubkeyN-1> OP_CHECKSIG

OP_IF

<voting_weightN-1>

OP_ADD

OP_ENDIF

OP_SWAP

<pubkeyN> OP_CHECKSIG

OP_IF

<voting_weightN>

OP_ADD

OP_ENDIF

<two_thirds_of_total_voting_weight>

OP_GREATERTHAN

The point of the script is that each SON has a weight (sum of votes for SON that is set at maintenance). The script goes through each SON and checks their signature. If the signature is present, their weight is added to the variable at the top of the stack. At the end, the the sum is compared to 2/3 of the total weight of all SONs. Depending on the cumulative weight of votes a decision is made on whether the transfer is to be executed. For the transfer to happen the sum of weights in the script must be >= 2/3 + 1 from the number of current active SON weights. All the variables in `<>` brackets change only when the set of SONs change, which is the same time as when the script is re-generated. Thus in the actual bitcoin script they will be literal constants.

Since the addresses depend on weights, and weights in turn depend on balances, on most occasions the deposit addresses will be re-generated after maintenance. There are two ways to handle this situation:

  1. All pre-maintenance are to be considered invalid after maintenance.

  2. Consider the pre-maintenance composition of SONs and their weights trusted post-maintenance. If the composition of SONs doesn't change, but their weights do, SON members are to be allowed to process the transaction in accordance with their pre-maintenance weights.

The maximum size of a Bitcoin script is 10kB, so with our limit of 15 SONs we will not approach this limit.

SON downtime and communication problems, handling of invalid transactions

Potential issues could arise on both the side of Bitcoin and PeerPlays. In case a transaction is sent on Bitcoin and is not added to mempool, and, by extension, Bitcoin blockchain, it is vital to avoid the depositors losing their BTC.

Potential issues include:

  1. Invalid serialization of a Bitcoin transaction.

  2. Bitcoin transaction uses invalid signatures.

  3. Bitcoin transaction uses invalid vin.

Detection of an invalid transaction

Before a transaction is sent to Bitcoin blockchain, SON memberplaces bitcoin_transaction_confirmations object with tx_id to an index in btc_sidechain_net_manager.

After receiving a block from Bitcoin, block counter bitcoin_transaction_confirmations::count_block increments in these objects. As soon as the counter reaches confirmations_num (specified in chain_parameters) transaction confirmation validation takes place.

  • Request to receive the number of confirmations (method bitcoin_rpc_client::receive_confirmations_tx). They are stored in bitcoin_transaction_confirmations::count_block , re-recording the previous data.

  • If the received number of confirmations >= confirmations_num, a transaction is considered confirmed.

  • If the number of confirmations = 0, it means that the transaction has not been added to the blockchain, and it is required to check if it is in Bitcoin mempool.

  • A request is made to check if a transaction is ino mempool (bitcoin_rpc_client::receive_mempool_entry_tx).

  • If it is in mempool, it is left as is, continuing to await confirmation.

  • If it is not in mempool, it is considered invalid, or a fork has occurred on Bitcoin.

Handling of an invalid transactions

  1. vins are checked for validity via bitcoin_rpc_client::receive_confirmations_tx.

  2. All invalid vins are dropped.

  3. All valid vins and vouts are added to btc_revert_operation and sent to the blockchain.

  4. Transaction object is removed from sidechain_net_manager::bitcoin_confirmations.

Handling btc_revert_operation

All valid objects btc_input_data_object and btc_withdrawal_data_object in the Evaluator class for this operation are marked as unused (unspent). Invalid btc_input_data_object and btc_transaction_object are deleted.

Therefore only valid input and withdrawals will be used in transactions on Bitcoin.

btc_revert_operation

This operation is used to restore information about transfers and removal of invalid information.

It contains the following fields:

Type

Name

Description

asset

fee

The fee for executing the operation on PeerPlays blockchain

account_id_type

payer

SON acount that pays for the operation

vector<revert_trx_info>

transactions_info

Information on transactions, stored as a vector

In the case of PeerPlays, potential issues arise when an active SON is disconnected and/or does not sign transactions due to the downtime, other SONs will need to sign transactions for him.

Borderline cases include:

  • Active SONs with the cumulative weights > 1/3 total active SONs weight do not sign transactions with deposit information or transactions outgoing from PW.

  • A SON wishes to stop performing their functions due to the required maintenance on his end

In the first case the operations of Sidechain will not be performed and Bitcoin transactions will be reverted as described above.

In the second case the SON is required to utilize remove_son_operation`. If they wish to return to the list of SONs and take part in SideChain operation, they will need to utilize create_son_operation`.

Primary wallet transfer during maintenance

When a new set of SONs is voted in, the primary wallet ownership has to be transferred to them. This involves multiple steps:

  • Creating a new Bitcoin script using the new SON keys and weights

  • Transferring any funds in the primary wallet to the new address

son-objects-and-operators

1. Purpose

The purpose of this document is to provide low-level design for creating new SON objects, updating the objects, listing them once created and voting for them.

2. Scope

The design requirement listed in this document will be limited to the creation of the new SON objects, updating the objects, listing the objects on CLI and voting for the objects.

The document will also outline the new data structures required to create and update the objects/accounts on the blockchain through UML diagrams.

The document will also outline the related function flow between modules through Sequence diagrams.

The document will also outline the roles of the accounts/users operating the SONs.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses. As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users. Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction. When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added. The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs). The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Disambiguation of types of users

This section tries to disambiguate the types of users registered on the current system and their roles.

4.1 Witness

Witnesses are the workhorses of the network.

The main task of the nodes is to gather the transactions, put them into a block, sign the block and broadcast it to network.

For each block produced by a witness, there is payment in core asset which is configured on the chain.

4.2 Workers

Workers are the group of users who maintain the network and introduce new features into the network.

4.3 Committee Members

Committee members are the unpaid volunteers that organize the community and propose changes to the network.

4.4 PPY Holders

PPY Holders are regular users who hold PPY in their accounts.

They can cast a vote and influence the decisions of the network.

4.5 SON Operators (new)

SON operators are the users that start a SON node on the network.

They can ask for votes from other users to be selected as top N SON operators. (N is currently proposed to be 15)

4.5.1 Roles and Requirements

  • These are the possible states for the new user role of SON,

    • Active SON - an account that is one of the top 15 voted SONs and is actively performing the operations of Sidechain.

    • Inactive SON - an account that is ready to perform the work required for Sidechain operation, but does not have the votes to be one of the top 15 votes SONs. An inactive SON can become active during a maintenance interval if it receives enough votes to become one of the top 15 voted SONs.

    • Maintenance_Requested SON - An SON account has requested for Maintenance and waiting for the maintenance interval for its account to be updated to In_Maintenance. SON-214 Done

    • In_Maintenance SON - An SON is in maintenance.

    • De-Registered SON - If an SON de-registers by itself through remove_son command or goes down abruptly and stays down for 12 hours or in maintenance for 12 hours, it is de-registered. (de-registered user will have to create the son node again using create_son )

  • Prospective SON operator's accounts should have a minimum amount of core asset (PPY) that needs to be vested in order to join the SONs. (50 PPY proposed currently)

  • SON Operator cannot reclaim the vested assets till after 2 days of deregistration of the node.

5. Design Changes Suggested

This section outlines the changes needed to realize the functionality of creation, update, and deletion of SON Nodes.

And it also outlines some of the Sequence diagrams of the use cases list_sons, vote_for_son.

Following is a brief overview of new data structures introduced,

5.1 son_object

This class holds all the information about SON and is stored in the DB.

son_create_operation creates the son object.

son_update_operation updates the son object.

son_delete_operation deletes the son object from DB.

5.2 son_create_operation

This class is used to create a son object in DB.

Whenever the SON creation is triggered this operation is pushed into a transaction.

It holds information like son_account, public block signing key.

5.3 son_update_operation

This class is used to update an already created son object in DB.

5.4 son_delete_operation

This class is used to delete an already created son object in DB.

5.5 son_create_evaluator

This class contains do_evaluate and do_apply functions which evaluate and apply the create operation respectively.

do_apply creates son_object in DB.

5.6 son_update_evaluator

This class contains do_evaluate and do_apply functions which evaluate and apply the update operation respectively.

do_evaluate checks for the son_object existence in DB.

do_apply updates the son_object with parameters supplied in son_update_operation.

5.7 son_delete_evaluator

This class contains do_evaluate and do_apply functions which evaluate and apply the update operation respectively.

do_evaluate checks for the son_object existence in DB.

do_apply deletes the son_object with parameters supplied in son_delete_operation.

5.7 vote_id_type (Enum)

A new vote type son is introduced which is needed in vote_for_son flow.

5.8 chain_parameters

A new extension parameter in chain_parameters maximum_son_count needs to be introduced with default value as 15 initially (proposed currently).

Later if the count has to be changed it can be done through committee_member_update_global_parameters_operation.

6. UML and Sequence Diagrams

7. CLI Wallet Commands

Following are the CLI Wallet commands to realize the functionality shown above,

7.1 Node Startup with SON Enabled

./programs/witness_node/witness_node --resync --replay --son_enable

The command enables the SON functionality in the node

7.2 Register as SON Node (wallet)

create_son <account_name> <proposal_url> true

The command registers the node on-chain and creates an ID

7.3 list_sons (wallet)

list_sons

The command lists all the account names that own SONs, active or inactive

7.4 vote_for_son (wallet)

vote_for_son <voting_account> <son_account> <approve> <broadcast>

The command allows voting in or out for a given SON account

7.5 update_son (wallet)

update_son <son_account> <proposal_url> <signing_key> <broadcast>

The command updates the created SON Object related to the SON account given

7.6 remove_son (wallet)

remove_son <son_account> <broadcast>

The command marks the SON Node as delete on-chain

Logo
Logo
Logo
Logo

bitcoin-sidechain-handler-lld

Objective

This document is intended to outline generic design of a blockchain handler, a component used for monitoring and processing changes on a Bitcoin network.

For general information on sidechain handlers, read: https://peerplays.atlassian.net/wiki/spaces/PIX/pages/352026689/Generic+Sidechain+Interface+High+Level+Design

Block Diagram

Link to draw.io file:

https://drive.google.com/file/d/1ErmQfeaWa9m67si4hb0RZs54WVYWR0pC/view?usp=sharing

Sequence diagram

Link to draw.io file

https://drive.google.com/file/d/17kbez7C1Djaj-2AgyEzQ1Z-5CrSZ5wZE/view?usp=sharing

Same sequence diagram applies for all sidechain handlers. It shows interactions between components in a single sidechain handler.

Components

The purpose of Bitcoin sidechain handler is to notify sidechain manager that a transaction of interest has happened, and forward the data about that transaction to it, for further processing. As stated in general design, standard components of the sidechain handler are listener, communication interface and event handler.

Listener

For general information on sidechain listeners, read: https://peerplays.atlassian.net/wiki/spaces/PIX/pages/352092181/Generic+Sidechain+Listener+HLD

Some of the info in this section are taken from useful article on ZMQ and Bitcoin https://bitcoindev.network/accessing-bitcoins-zeromq-interface/

Assumptions

Blockchain node provides interface for monitoring changes in a blockchain.

Bitcoin node provides ZeroMQ messaging interface. The ZeroMQ facility implements a notification interface through a set of specific notifiers. Currently there are notifiers that publish blocks and transactions. This read-only facility requires only the connection of a corresponding ZeroMQ subscriber port in receiving software; it is not authenticated nor is there any two-way protocol involvement. Therefore, subscribers should validate the received data since it may be out of date, incomplete or even invalid.

Monitoring is based on new block, new transaction or filtered single event (like transfer operation to specific address)

Bitcoin's ZMQ uses a publish/subscribe (pubsub) design pattern, where the publisher in our case is our bitcoin node which published messages based on events. The subscriber on the other hand, includes any application looking to utilise it by subscribing to these events. There are currently 4 different publish (PUB) notification topics we can expose via bitcoind which notify us when ever a new block or transaction is validated by the node.

  • zmqpubhashtx : Publishes transaction hashes

  • zmqpubhashblock : Publishes block hashes

  • zmqpubrawblock : Publishes raw block information

  • zmqpubrawtx : Publishes raw transaction information

We can use any of these, but some are more practical than others. E.g. we can subscribe to receive hash values of newly created blocks:

socket.setsockopt( ZMQ_SUBSCRIBE, "hashblock", 0 );

socket.connect( "tcp://" + ip + ":" + std::to_string( zmq_port ) );

zmqpubrawtx looks like best candidate we can use, since we can get raw transaction info, decode it, and we will have all required info in a single call. However, depending on number of transaction, we can expect more traffic between bitcoin node and listener.

zmqpubhashblock is also a good candidate, we will receive the hash of newly created block, then we can read the whole block by communication interface, parse it and get the info we need.

There is a sufficient C/C++ library for connecting to monitoring interface

ZeroMQ project provides a client library which we can use to connect to a Bitcoin node ZeroMQ interface. The project is alive and well maintained. At the time of writing this document, we are not aware of any problem which would require us to use specific library version, or link it statically into our software.

https://zeromq.org/

https://github.com/zeromq/libzmq

There is a libzmq3-dev package in Ubuntu 18.04 repository.

https://packages.ubuntu.com/bionic/libzmq3-dev

This will be obvious developers choice, for ease of installation and usage.

Communication interface

Bitcoin provides RPC interface we can use to read additional transaction info from a node.

Depending on how we configure the listener, we will need more or less functionalities in this component.

In general, we will need:

  • Method to retrieve the whole block by hash

    • https://bitcoin.org/en/developer-reference#getblock

  • Method to retrieve the transaction by hash

    • https://bitcoin.org/en/developer-reference#gettransaction

  • Method to retrieve block as json

    • HTTP request to "http://ip/:PORT/rest/block/BLOCK_HASH.json"

  • Method to decode transaction

    • https://bitcoin.org/en/developer-reference#decoderawtransaction

  • Method to retrieve the transaction fee

    • https://bitcoin.org/en/developer-reference#estimatesmartfee

  • Method to send signed transaction to the node (for deposit/withdrawal)

    • https://bitcoin.org/en/developer-reference#sendrawtransaction

Communication interface can be implemented as a HTTP client, which will send requests to a bitcoin node.

Event Handler

Event handler is a working horse of sidechain handler. It will receive input from a listener, and process it any way needed, in order to get the minimum required information about event of interest, namely transactions to the addresses we are interested in.

In general, event handler needs:

  • Access to the list of addresses we are interested in

Suggested implementation

  • sidechain_manager is a class implementing Sidechain Manager

    • Introduce a new element of network enum, to indicate that we want to use bitcoin network

    • namespace graphene { namespace peerplays_sidechain {

    • enum networks {

    • bitcoin

    • ...

    • };

    • class sidechain_net_manager {

...

    • Extend factory method to create the instance of sidechain_handler_bitcoin

    • bool sidechain_net_manager::create_handler(peerplays_sidechain::networks network, const boost::program_options::variables_map& options) {

    • ...

    • switch (network) {

    • case networks::bitcoin: {

    • std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_bitcoin(options));

    • net_handlers.push_back(std::move(h));

    • ret_val = true;

    • }

    ...

  • Implement sidechain_handler_bitcoin class, inheriting sidechain_handler, implementing sidechain handler for Bitcoin

  • Implement zmq_listener, using ZeroMQ library

    • subsribe to hashblock or raw transaction

    • socket.setsockopt( ZMQ_SUBSCRIBE, "hashblock", 0 );

    • socket.connect( "tcp://" + ip + ":" + std::to_string( zmq_port ) );

      • or

      • socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 0 );

    socket.connect( "tcp://" + ip + ":" + std::to_string( zmq_port ) );

  • Implement bitcoin_rpc_client class, HTTP client used to communicate with Bitcoin node

    • Implement, at least, following methods:

      • receive_full_block - to retrieve full block by block hash

      • receive_transaction - to retrieve transaction info by transaction hash

      • receive_block_as_json - to retrieve full block as json by block hash

      • decode_transaction - to decode raw bitcoin trasnaction

      • receive_estimated_fee - to retrieve transaction cost (transaction fee)

      • send_btc_tx - to send signed transaction to the bitcon node

  • Implement any additional code needed, for receiving event data, collecting any additional information about event of interest, with the final result as a data structure containing the following info:

  • struct sidechain_transaction_info {

  • graphene::peerplays_sidechain::networks network; // set to network::bitcoin

  • std::string source;

  • std::string destination;

  • uint64_t amount;

  • uint64_t transaction_fee;

}

    • Identifier of a sidechain handler (network::bitcoin)

    • Transaction’s source address (as string, representing sidechain native address)

    • Transaction’s destination address (as string, representing sidechain native address)

    • Transaction’s amount (as unsigned integer, in sidechain native currency)

    • Estimated transaction fee (as unsigned integer, in sidechain native currency)

General Calls

This page documents the BookiePro data abstraction layer with the Peerplays blockchain.

BookiePro communicates with the blockchain using web-socket API calls.

list_sports

Get a list of available sports.

Apis.instance().db_api().exec( "list_sports", [] )

A list of all the available sports.

ChainStore.getSportsList = function getSportsList() {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().db_api().exec('list_sports', []).then(function (sportsList) {
        if (sportsList) {
          resolve(sportsList);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

list_event_groups

Get a list of all event groups for a sport, for example, all soccer leagues in soccer.

Apis.instance().db_api().exec( "list_event_groups", [sportId] )

sportId: The id of the sport that the event groups are to be listed for.

A list of all event groups for the selected sport.

ChainStore.prototype.getEventGroupsList = function getEventGroupsList(sportId) {
    var _this17 = this;

    var eventGroupsList = this.event_groups_list_by_sport_id.get(sportId);

    if (eventGroupsList === undefined) {
      this.event_groups_list_by_sport_id = this.event_groups_list_by_sport_id.set(sportId, _immutable2.default.Set());

      _ws.Apis.instance().db_api().exec('list_event_groups', [sportId]).then(function (eventGroups) {
        var set = new Set();

        for (var i = 0, len = eventGroups.length; i < len; ++i) {
          set.add(eventGroups[i]);
        }

        _this17.event_groups_list_by_sport_id = _this17.event_groups_list_by_sport_id.set(sportId, _immutable2.default.Set(set));
        _this17.notifySubscribers();
      }, function () {
        _this17.event_groups_list_by_sport_id = _this17.event_groups_list_by_sport_id.delete(sportId);
      });
    }

    return this.event_groups_list_by_sport_id.get(sportId);
  };

list_betting_market_groups

Get a list of all betting market groups for an event, for example, Moneyline and OVER/UNDER for soccer)

Apis.instance().db_api().exec( "list_betting_market_groups", [eventId] )

eventId: The id of the event that the betting market groups are to be listed for.

A list of all the betting market groups for the event.

ChainStore.prototype.getBettingMarketGroupsList = function getBettingMarketGroupsList(eventId) {
    var _this18 = this;

    var bettingMarketGroupsList = this.betting_market_groups_list_by_sport_id.get(eventId);

    if (bettingMarketGroupsList === undefined) {
      this.betting_market_groups_list_by_sport_id = this.betting_market_groups_list_by_sport_id.set(eventId, _immutable2.default.Set());

      _ws.Apis.instance().db_api().exec('list_betting_market_groups', [eventId]).then(function (bettingMarketGroups) {
        var set = new Set();

        for (var i = 0, len = bettingMarketGroups.length; i < len; ++i) {
          set.add(bettingMarketGroups[i]);
        }

        _this18.betting_market_groups_list_by_sport_id = _this18.betting_market_groups_list_by_sport_id.set( // eslint-disable-line
        eventId, _immutable2.default.Set(set));
        _this18.notifySubscribers();
      }, function () {
        _this18.betting_market_groups_list_by_sport_id = _this18.betting_market_groups_list_by_sport_id.delete( // eslint-disable-line
        eventId);
      });
    }

    return this.betting_market_groups_list_by_sport_id.get(eventId);
  };

list_betting_markets

Get a list of all betting markets for a betting market group (BMG).

Apis.instance().db_api().exec( "list_betting_markets", [bettingMarketGroupId] )

bettingMarketGroupId: The id of the betting market group that the betting markets are to be listed for.

A list of all the betting markets for the betting market group.

ChainStore.prototype.getBettingMarketsList = function getBettingMarketsList(bettingMarketGroupId) {
    var _this19 = this;

    var bettingMarketsList = this.betting_markets_list_by_sport_id.get(bettingMarketGroupId);

    if (bettingMarketsList === undefined) {
      this.betting_markets_list_by_sport_id = this.betting_markets_list_by_sport_id.set(bettingMarketGroupId, _immutable2.default.Set());

      _ws.Apis.instance().db_api().exec('list_betting_markets', [bettingMarketGroupId]).then(function (bettingMarkets) {
        var set = new Set();

        for (var i = 0, len = bettingMarkets.length; i < len; ++i) {
          set.add(bettingMarkets[i]);
        }

        _this19.betting_markets_list_by_sport_id = _this19.betting_markets_list_by_sport_id.set(bettingMarketGroupId, _immutable2.default.Set(set));
        _this19.notifySubscribers();
      }, function () {
        _this19.betting_markets_list_by_sport_id = _this19.betting_markets_list_by_sport_id.delete(bettingMarketGroupId);
      });
    }

    return this.betting_markets_list_by_sport_id.get(bettingMarketGroupId);
  };

get_global_betting_statistics

Get global betting statistics

Apis.instance().db_api().exec( "get_global_betting_statistics", [] )

A list of all the global betting statistics.

ChainStore.getGlobalBettingStatistics = function getGlobalBettingStatistics() {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().db_api().exec('get_global_betting_statistics', []).then(function (getGlobalBettingStatistics) {
        if (getGlobalBettingStatistics) {
          resolve(getGlobalBettingStatistics);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_binned_order_book

Get the binned order book for a betting market.

Apis.instance().bookie_api().exec( "get_binned_order_book", [ betting_market_id, precision ] )
  • betting_market_id: The id of the betting market for the order book.

  • precision: Precision

A list of binned orders for the betting market.

ChainStore.getBinnedOrderBook = function getBinnedOrderBook(betting_market_id, precision) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().bookie_api().exec('get_binned_order_book', [betting_market_id, precision]).then(function (order_book_object) {
        if (order_book_object) {
          resolve(order_book_object);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_total_matched_bet_amount_for_betting_market_group

Get the total matched bets for a betting market group (BMG).

Apis.instance().bookie_api().exec( "get_total_matched_bet_amount_for_betting_market_group", [ group_id ] )
  • group_id: The betting market group id.

Total of all the matched bet amounts for the selected betting market group.

ChainStore.getTotalMatchedBetAmountForBettingMarketGroup = function getTotalMatchedBetAmountForBettingMarketGroup(group_id) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().bookie_api().exec('get_total_matched_bet_amount_for_betting_market_group', [group_id]).then(function (total_matched_bet_amount) {
        if (total_matched_bet_amount) {
          resolve(total_matched_bet_amount);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_events_containing_sub_string

Used to search for events.

Apis.instance().bookie_api().exec( "get_events_containing_sub_string", [ sub_string, language ])
  • sub_string: The (sub) string of text to search for

  • language: Language id.

List of events that contain the sub-string

function getEventsContainingSubString(sub_string, language) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().bookie_api().exec('get_events_containing_sub_string', [sub_string, language]).then(
        function (events_containing_sub_string) {
        if (events_containing_sub_string) {
          resolve(events_containing_sub_string);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_unmatched_bets_for_bettor

Get unmatched bets for a bettor.

Apis.instance().bookie_api().exec( "get_matched_bets_for_bettor", [ bettor_id ] )
  • bettor_id: The id of the bettor.

List of all matched bets for a bettor.

ChainStore.getUnmatchedBetsForBettor = function getUnmatchedBetsForBettor(betting_market_id_type, account_id_type) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().db_api().exec('get_unmatched_bets_for_bettor', [betting_market_id_type, account_id_type]).then(function (unmatched_bets_for_bettor) {
        if (unmatched_bets_for_bettor) {
          resolve(unmatched_bets_for_bettor);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

list_events_in_group

Get a list of events in any event group.

Apis.instance().db_api().exec( "list_events_in_group", [ event_group_id ] )
  • event_group_id: The id of the event group.

A list of all the events in the event group.

 ChainStore.listEventsInGroup = function listEventsInGroup(event_group_id) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().db_api().exec('list_events_in_group', [event_group_id]).then(function (events_in_group) {
        if (events_in_group) {
          resolve(events_in_group);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_all_unmatched_bets_for_bettor

Get all unmatched bets of a bettor according to account type.

Apis.instance().db_api().exec( "get_all_unmatched_bets_for_bettor", [ account_id_type ] )
  • account_type_id: The id of the bettor account type/

All unmatched bets by bettor account type.

ChainStore.getAllUnmatchedBetsForBettor = function getAllUnmatchedBetsForBettor(account_id_type) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().db_api().exec('get_all_unmatched_bets_for_bettor', [account_id_type]).then(function (all_unmatched_bets_for_bettor) {
        if (all_unmatched_bets_for_bettor) {
          resolve(all_unmatched_bets_for_bettor);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_matched_bets_for_bettor

Get the matched bets for a bettor.

Apis.instance().bookie_api().exec( "get_matched_bets_for_bettor", [ bettor_id ] )
  • bettor_id: The id of the bettor.

All matched bets for the bettor.

ChainStore.getMatchedBetsForBettor = function getMatchedBetsForBettor(bettor_id) {
    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().bookie_api().exec('get_matched_bets_for_bettor', [bettor_id]).then(function (matched_bets_for_bettor) {
        if (matched_bets_for_bettor) {
          resolve(matched_bets_for_bettor);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

get_all_matched_bets_for_bettor

Get all matched bets for a bettor within a range.

Apis.instance().bookie_api().exec( "get_all_matched_bets_for_bettor", [ bettor_id, start, limit ] )
  • bettor_id: The id of the bettor

  • start: The start date

  • limit: Number of bets to be returned

All matched bets for the better within the range start to limit.

ChainStore.getAllMatchedBetsForBettor = function getAllMatchedBetsForBettor(bettor_id, start) {
    var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;

    return new Promise(function (resolve, reject) {
      _ws.Apis.instance().bookie_api().exec('get_all_matched_bets_for_bettor', [bettor_id, start, limit]).then(function (all_matched_bets_for_bettor) {
        if (all_matched_bets_for_bettor) {
          resolve(all_matched_bets_for_bettor);
        } else {
          resolve(null);
        }
      }, reject);
    });
  };

generic-sidechain-high-level-design

Objective

This document is intended to outline generic design of sidechain plugin used by Peerplays Node, to monitor and process events of interest on a target sidechain nodes. This interface will be extended to meet various other integrations.

Assumptions

  • Sidechain plugin purpose is to monitor and process events of interest on a multiple target sidechains.

  • Sidechain node provides interface for monitoring changes in a sidechain.

  • Monitoring is based on new block, new transaction or filtered single event (like transfer operation to specific address).

  • There is a sufficient C/C++ library for connecting to monitoring interface.

  • Sidechain node provides communication interface which sidechain handler can use to read all the required info about event of interest. E.g. HTTP/RPC…

Block Diagram

Link to Draw.io file

https://drive.google.com/file/d/1BXeRwK_2PNt6wMnzIl8M6OMRnuM5CumQ/view?usp=sharing

Description

  • Peerplays Sidechain is implemented as a plugin.

  • Sidechain Manager is a component in a Peerplays Plugin, which contains a collection of Sidechain Handlers.

  • No multiple sidechain handlers for same network is allowed.

  • No communication between sidechain handlers is allowed or needed.

  • One Sidechain Handler handles only one sidechain network.

  • Each Sidechain Handler monitors and processes events of interests on its target network.

  • Each Sidechain Handler implements only sidechain specific processing, eg reading transaction info, parsing transaction data, etc…

  • The result of Sidechain Handler processing saved into peerplays network for further processing

  • In general, Sidechain Handler contains event listener, communication interface and event handler.

  • Event listener is “listening” for events on a sidechain. When event happens, event listener will notify event handler about incoming event.

  • Event handler uses communication interface to read all the information needed in order to process the event.

  • Once the processing is finished, event handler will pass the result to the Sidechain Manager, for further processing.

Sequence diagram

Link to draw.io file

https://drive.google.com/file/d/17kbez7C1Djaj-2AgyEzQ1Z-5CrSZ5wZE/view?usp=sharing

For the simplicity, sequence diagram shows interactions between components in a single sidechain handler.

Suggested implementation

  • peerplays_sidechain_plugin is a class implementing a peerplays sidechain plugin.

    • Contains the instance of sidechain_manager

  • sidechain_manager is a class implementing Sidechain Manager

    • Contains the collection (std::vector) of sidechain_handlers

    • Contains the factory method for creating instance of sidechain_handler for particular sidechain

    • Factory method parameters include program options, used to pass configure options to a sidechain handler

    • Contains methods for calling sidechain_handlers methods for processing events of interest

    • recreate_primary_wallet This method will initiate recreation of primary wallet on active SON set change, if needed

    • process_deposits This method will call sidechain handlers method for processing sidechain deposits

    • process_withdrawals This method will call sidechain handlers method for processing sidechain withdrawals

  • sidechain_handler is a base class for implementing sidechain handlers

    • Needs to have access to user sidechain address mapping list, in order to filter events by checking addresses involved in a transaction against the list of addresses of interests.

      • sidechain_type get_sidechain() Gets the sidechain type

      • std::vectorstd::string get_sidechain_deposit_addresses() Gets the list of deposit addresses for a sidechain

      • std::vectorstd::string get_sidechain_withdraw_addresses() Gets the list of withdrawal addresses for a sidechain

      • std::string get_private_key(std::string public_key) Gets the private key for a given public key, for signing sidechain transactions

    • Needs to contain method receiving the data structure describing event of interest as the parameter

      • sidechain_event_data_received(const sidechain_event_data &sed)

      • // Sidechain type

      • enum class sidechain_type {

      • bitcoin,

      • ethereum,

      • eos,

      • peerplays

      • };

      • struct sidechain_event_data {

      • fc::time_point_sec timestamp; // time when event was detected

      • sidechain_type sidechain; // sidechain where event happened

      • std::string sidechain_uid; // transaction unique id for a sidechain

      • std::string sidechain_transaction_id; // transaction id on a sidechain

      • std::string sidechain_from; // sidechain senders account, if available

      • std::string sidechain_to; // sidechain receiver account, if available

      • std::string sidechain_currency; // sidechain transfer currency

      • fc::safe<int64_t> sidechain_amount; // sidechain asset amount

      • chain::account_id_type peerplays_from; // perplays senders account matching sidechain senders account

      • chain::account_id_type peerplays_to; // peerplays receiver account matching sidechain receiver account

      • chain::asset peerplays_asset; // transfer value in peerplays core asset

};

    • For deposits, sidechain handler will create deposit descriptor object son_wallet_deposit_object, using data from sidechain_evend_data structure

    • class son_wallet_deposit_object : public abstract_object<son_wallet_deposit_object>

    • {

    • public:

    • static const uint8_t space_id = protocol_ids;

    • static const uint8_t type_id = son_wallet_deposit_object_type;

    • time_point_sec timestamp;

    • peerplays_sidechain::sidechain_type sidechain;

    • int64_t confirmations;

    • std::string sidechain_uid;

    • std::string sidechain_transaction_id;

    • std::string sidechain_from;

    • std::string sidechain_to;

    • std::string sidechain_currency;

    • safe<int64_t> sidechain_amount;

    • chain::account_id_type peerplays_from;

    • chain::account_id_type peerplays_to;

    • chain::asset peerplays_asset;

    • bool processed;

    };

    • For withdrawals, sidechain handler will create withdrawal descriptor object son_wallet_withdraw_object, using data from sidechain_event_data structure

    • class son_wallet_withdraw_object : public abstract_object<son_wallet_withdraw_object>

    • {

    • public:

    • static const uint8_t space_id = protocol_ids;

    • static const uint8_t type_id = son_wallet_withdraw_object_type;

    • time_point_sec timestamp;

    • peerplays_sidechain::sidechain_type sidechain;

    • int64_t confirmations;

    • std::string peerplays_uid;

    • std::string peerplays_transaction_id;

    • chain::account_id_type peerplays_from;

    • chain::asset peerplays_asset;

    • peerplays_sidechain::sidechain_type withdraw_sidechain;

    • std::string withdraw_address;

    • std::string withdraw_currency;

    • safe<int64_t> withdraw_amount;

    • bool processed;

    };

    • Contains following abstract methods (the list can change anytime):

      • virtual void recreate_primary_wallet() = 0; Method is called by sidechain manager, to recreate the primary wallet on a sidechain, if needed

      • virtual void process_deposit(const son_wallet_deposit_object &swdo) = 0; Callback method, called for each deposit that needs to be processed by a sidechain handler

      • virtual void process_withdrawal(const son_wallet_withdraw_object &swwo) = 0;

      • Callback method, called for each withdrawal that needs to be processed by a sidechain handler

  • sidechain_handler_bitcoin is a class, inheriting sidechain_handler, implementing sidechain handler for Bitcoin

    • Listener may be implemented by ZeroMQ (also spelled ØMQ, 0MQ or ZMQ), high-performance asynchronous messaging library

    • Communication interface may be implemented as HTTP client, using RPC bitcoin node interface

      • Implement any RPC call that might be needed

      • std::string addmultisigaddress(const std::vector<std::string> public_keys);

      • std::string createrawtransaction(const std::vector<btc_txout> &ins, const fc::flat_map<std::string, double> outs);

      • std::string createwallet(const std::string &wallet_name);

      • std::string encryptwallet(const std::string &passphrase);

      • uint64_t estimatesmartfee();

      • std::string getblock(const std::string &block_hash, int32_t verbosity = 2);

      • void importaddress(const std::string &address_or_script);

      • std::vector<btc_txout> listunspent();

      • std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount);

      • std::string loadwallet(const std::string &filename);

      • void sendrawtransaction(const std::string &tx_hex);

      • std::string signrawtransactionwithkey(const std::string &tx_hash, const std::string &private_key);

      • std::string signrawtransactionwithwallet(const std::string &tx_hash);

      • std::string unloadwallet(const std::string &filename);

    std::string walletlock();

    • Implements abstract methods:

      • void recreate_primary_wallet() override; Method is called by sidechain manager, to recreate the primary wallet on a sidechain, if needed

      • void process_deposit(const son_wallet_deposit_object &swdo) override; Callback method, called for each deposit that needs to be processed by a sidechain handler

      • void process_withdrawal(const son_wallet_withdraw_object &swwo) override; Callback method, called for each withdrawal that needs to be processed by a sidechain handler

  • sidechain_handler_ethereum is a class, inheriting sidechain_handler, implementing sidechain handler for Ethereum

    • TBD

  • sidechain_handler_eos is a class, inheriting sidechain_handler, implementing sidechain handler for EOS

    • TBD

  • sidechain_handler_peerplays is a class, inheriting sidechain_handler, implementing sidechain handler for Peerplays

    • Listener can be implemented as a callback of database.applied_block signal. This will give us access to newly created blocks, and its content.

    • Communication interface, like RPC client from Bitcoin handler, is not really needed, as we can read all the data we need from blockchain database.

    • Implements abstract methods:

      • void recreate_primary_wallet() override; Method is called by sidechain manager, to recreate the primary wallet on a sidechain, if needed

      • void process_deposit(const son_wallet_deposit_object &swdo) override; Callback method, called for each deposit that needs to be processed by a sidechain handler

      • void process_withdrawal(const son_wallet_withdraw_object &swwo) override; Callback method, called for each withdrawal that needs to be processed by a sidechain handler

  • sidechain_handler_* is a class, inheriting sidechain_handler, implementing sidechain handler for *

    • Any future sidechain

    • TBD

getnewaddress — Bitcoin
Testing Applications — Bitcoin
bitcoin-cli getnewaddress – ChainQuery
CLI Commands for SONsPeerplays Infrastructure Docs
bitcoin-cli getaddressinfo – ChainQuery
getaddressinfo — Bitcoin

Popular API Calls

Overview

Some of the most interesting API calls for exchanges and gateways are listed in this document.

We will now take a look at some sample outputs for some of the API calls.

API Calls

list_account_balances

List the balances of an account. Each account can have multiple balances, one for each type of asset owned by that account. The returned list will only contain assets for which the account has a nonzero balance.

  • id: the name or id of the account whose balances you want

A list of the given account’s balances.

transfer

Transfer an amount from one account to another.

  • from: the name or id of the account sending the funds

  • to: the name or id of the account receiving the funds

  • amount: the amount to send (in nominal units to send half of a BTS, specify 0.5)

  • asset_symbol: the symbol or id of the asset to send

  • memo: a memo to attach to the transaction. The memo will be encrypted in the transaction and readable for the receiver. There is no length limit other than the limit imposed by maximum transaction size, but transaction increase with transaction size

  • broadcast: true to broadcast the transaction on the network

The final parameter True states that the signed transaction will be broadcast. If this parameter is False the transaction will be signed but not broadcast, hence not executed.

The signed transaction transferring funds.

transfer2

This method works just like transfer, except it always broadcasts and returns the transaction ID (hash) along with the signed transaction.

  • from: the name or id of the account sending the funds

  • to: the name or id of the account receiving the funds

  • amount: the amount to send

  • asset_symbol: the symbol or id of the asset to send

  • memo: a memo to attach to the transaction. The memo will be encrypted in the transaction and readable for the receiver. There is no length limit other than the limit imposed by maximum transaction size, but transaction increase with transaction size

The transaction ID (hash) along with the signed transaction transferring funds

get_account_history

Returns the most recent operations on the named account.

This returns a list of operation history objects, which describe activity on the account.

  • name: the name or id of the account

  • limit: the number of entries to return (starting from the most recent)

A list of operation_history_objects.

get_object

Returns the blockchain object corresponding to the given id.

This generic function can be used to retrieve any object from the blockchain that is assigned an ID. Certain types of objects have specialized convenience functions to return their objects e.g., assets have , accounts have , but this function will work for any object.

  • id: the id of the object to return

The requested object.

get_asset

Returns information about the given asset.

  • asset_name_or_id: the symbol or id of the asset in question

The information about the asset stored in the block chain.

vector<asset> graphene::wallet::wallet_api::list_account_balances(
    const string &id)
signed_transaction graphene::wallet::wallet_api::transfer(
    string from, 
    string to, 
    string amount, 
    string asset_symbol, 
    string memo, 
    bool broadcast = false)
import json
from grapheneapi import GrapheneAPI
client = GrapheneAPI("localhost", 8092, "", "")
res = client.transfer("fromaccount","toaccount","10", "USD", "$10 gift", True);
print(json.dumps(res,indent=4))
{
  "ref_block_num": 18,
  "ref_block_prefix": 2320098938,
  "expiration": "2015-10-13T13:56:15",
  "operations": [[
      0,{
        "fee": {
          "amount": 2089843,
          "asset_id": "1.3.0"
        },
        "from": "1.2.17",
        "to": "1.2.7",
        "amount": {
          "amount": 10000000,
          "asset_id": "1.3.0"
        },
        "memo": {
          "from": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
          "to": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
          "nonce": "16430576185191232340",
          "message": "74d0e455e2e5587b7dc85380102c3291"
        },
        "extensions": []
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "1f147aed197a2925038e4821da54bd7818472ebe25257ac9a7ea66429494e7242d0dc13c55c6840614e6da6a5bf65ae609a436d13a3174fd12f073550f51c8e565"
  ]
}
pair<transaction_id_type, signed_transaction> graphene::wallet::wallet_api::transfer2(
    string from, 
    string to, 
    string amount, 
    string asset_symbol, 
    string memo)
import json
from grapheneapi import GrapheneAPI
client = GrapheneAPI("localhost", 8092, "", "")
res = client.transfer2("fromaccount","toaccount","10", "USD", "$10 gift");
print(json.dumps(res,indent=4))
 [b546a75a891b5c51de6d1aafd40d10e91a717bb3,{
   "ref_block_num": 18,
   "ref_block_prefix": 2320098938,
   "expiration": "2015-10-13T13:56:15",
   "operations": [[
       0,{
         "fee": {
           "amount": 2089843,
           "asset_id": "1.3.0"
         },
         "from": "1.2.17",
         "to": "1.2.7",
         "amount": {
           "amount": 10000000,
           "asset_id": "1.3.0"
         },
         "memo": {
           "from": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
           "to": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
           "nonce": "16430576185191232340",
           "message": "74d0e455e2e5587b7dc85380102c3291"
         },
         "extensions": []
       }
     ]
   ],
   "extensions": [],
   "signatures": [
     "1f147aed197a2925038e4821da54bd7818472ebe25257ac9a7ea66429494e7242d0dc13c55c6840614e6da6a5bf65ae609a436d13a3174fd12f073550f51c8e565"
   ]
 }
]
vector<operation_detail> graphene::wallet::wallet_api::get_account_history(
    string name, 
    int limit)const
import json
from grapheneapi import GrapheneAPI
client = GrapheneAPI("localhost", 8092, "", "")
res = client.get_account_history("dan", 1)
print(json.dumps(res,indent=4))
[
     {
         "description": "fill_order_operation dan fee: 0 CORE",
         "op": {
             "block_num": 28672,
             "op": [
                 4,
                 {
                     "pays": {
                         "asset_id": "1.3.536",
                         "amount": 20000
                     },
                     "fee": {
                         "asset_id": "1.3.0",
                         "amount": 0
                     },
                     "order_id": "1.7.1459",
                     "account_id": "1.2.21532",
                     "receives": {
                         "asset_id": "1.3.0",
                         "amount": 50000000
                     }
                 }
             ],
             "id": "1.11.213277",
             "trx_in_block": 0,
             "virtual_op": 47888,
             "op_in_trx": 0,
             "result": [
                 0,
                 {}
             ]
         },
         "memo": ""
     }
 ]
variant graphene::wallet::wallet_api::get_object(
    object_id_type id)const
import json
from grapheneapi import GrapheneAPI
client = GrapheneAPI("localhost", 8092, "", "")
res = client.get_object("1.11.213277")
print(json.dumps(res,indent=4))
{
    "trx_in_block": 0,
    "id": "1.11.213277",
    "block_num": 28672,
    "op": [
        4,
        {
            "fee": {
                "asset_id": "1.3.0",
                "amount": 0
            },
            "receives": {
                "asset_id": "1.3.0",
                "amount": 50000000
            },
            "pays": {
                "asset_id": "1.3.536",
                "amount": 20000
            },
            "account_id": "1.2.21532",
            "order_id": "1.7.1459"
        }
    ],
    "result": [
        0,
        {}
    ],
    "op_in_trx": 0,
    "virtual_op": 47888
}
extended_asset_object graphene::wallet::wallet_api::get_asset(
    string asset_name_or_id)const
import json
from grapheneapi import GrapheneAPI
client = GrapheneAPI("localhost", 8092, "", "")
res = client.get_asset("USD")
print(json.dumps(res,indent=4))
{
    "symbol": "USD",
    "issuer": "1.2.1",
    "options": {
        "description": "1 United States dollar",
        "whitelist_authorities": [],
        "flags": 0,
        "extensions": [],
        "core_exchange_rate": {
            "quote": {
                "asset_id": "1.3.536",
                "amount": 11
            },
            "base": {
                "asset_id": "1.3.0",
                "amount": 22428
            }
        },
        "whitelist_markets": [],
        "max_supply": "1000000000000000",
        "blacklist_markets": [],
        "issuer_permissions": 79,
        "market_fee_percent": 0,
        "max_market_fee": "1000000000000000",
        "blacklist_authorities": []
    },
    "dynamic_asset_data_id": "2.3.536",
    "bitasset_data_id": "2.4.32",
    "id": "1.3.536",
    "precision": 4
}
get_asset()
get_account()
import json
from grapheneapi import GrapheneAPI
client = GrapheneAPI("localhost", 8092, "", "")
res = client.list_account_balances("dan")
print(json.dumps(res,indent=4))
[
    {
        "asset_id": "1.3.0",
        "amount": "331104701530"
    },
    {
        "asset_id": "1.3.511",
        "amount": 3844848635
    },
    {
        "asset_id": "1.3.427",
        "amount": 8638
    },
    {
        "asset_id": "1.3.536",
        "amount": 31957981
    }
]

exchange-rate-list

Exchange rate list is a component containing exchange rates between 1 unit of target sidechain native currency and pBTC. Exchange rates are used during deposit and withdrawal process, for calculating how much pBTC should be issued for a given amount of sidechain native currency, or how much sidechain native currency should be paid to the user for a given amount of pBTC.

Exchange rate list operations should be implemented in core, not in a plugin. Using exchange rate list operations should not be allowed to all users. E.g. only committee members or Peerplays network administrators may use them. However, handling exchange rates as proposals, and waiting for network members to vote, may not be the best solution, as the circumstances might require that exchange rate becomes active immediately, to prevent network misuse, or pulling funds on unfair conditions (e.g. when currency value variations are too high, or a lot of users start pulling funds out of the network).

Access to functions to add, update or delete exchange rate, should not be allowed to all users on the network, but only to users which are considered Peerplays network adminsitrators, or committee members.

Requirements

  • Exchange rate list contains exchange rates between 1 unit of target sidechain native currency and pBTC.

  • All values are stored as int64_t (or uint_64_t, still to decide), and expressed in minimal currency units (1 BTC = 100000000 Satoshi’s, 1 ETH = 1000000000000000000 wei’s, 1 EOS = 1000 whatever, etc…)

  • Exchange rate can be added, deleted and updated by authorized entity (user or SON network)

  • Exchange rate list can be expanded with timestamp field, showing UTC date and time from when the exchange rate should be used. Version with timestamp is harder to implement and maintain.

  • Exchange rate list operations

    • create_exchange_rate - creates exchange rate

    • update_exchange_rate - updates exchange rate

    • delete_exchange_rate - deletes exchange rate

  • Exchange rate wallet functions

    • create_exchange_rate - creates exchange rate

    • update_exchange_rate - updates exchange rate

    • delete_exchange_rate - deletes exchange rate

    • get_exchange_rate - gets a single exchange rate (by id, or network, or network and timestamp)

    • list_exchange_rates - lists all exchange rates

Examples of exchange rate list

Following table shows simplest exchange rate list with no saved history of exchange rates

Currency

Currency amount

pBTC amount

BTC

100000000

X

EOS

1000

Y

ETH

1000000000000000000

Z

Following table shows exchange rate list, expanded with timestamp field, which is able to save exchange rate history

BTC

2019-11-20 00:00:00

100000000

X

BTC

2019-11-25 00:00:00

100000000

X1

EOS

2019-11-20 10:00:00

1000

Y

EOS

2019-11-24 14:00:00

1000

Y1

ETH

2019-11-21 07:00:00

1000000000000000000

Z

ETH

2019-11-23 00:00:00

1000000000000000000

Z1

Implementation

Consider the following code as a suggestion, not as a 100% completed ad working implementation. Syntax errors may be present.

Following declaration needs to be moved from SON plugin, to the core:

enum networks {

bitcoin,

eos,

ethereum

};

Exchange rate object:

class exchange_rate_object : public graphene::db::abstract_object<exchange_rate_object> {

uint32_t exchange_rate_id; // Primary key

network network; // Network managing the currency

int64_t exchange_from; // Network native currency amount

int64_t exchange_to; // Peerplays asset amount (pBTC)

}

// Version with timestamp

class exchange_rate_object : public graphene::db::abstract_object<exchange_rate_object> {

uint32_t exchange_rate_id; // Primary key

network network; // Network managing the currency

time_point_sec valid_from; // Starting date when exchange rate becomes valid

int64_t exchange_from; // Network native currency amount

int64_t exchange_to; // Peerplays asset amount (pBTC)

}

Exchange rate list index:

struct by_network;

using exchange_rate_multi_index_type = multi_index_container<

exchange_rate_object,

indexed_by<

ordered_unique< tag<by_id>,

member<object, object_id_type, &object::id>

>,

ordered_unique< tag<by_network>,

member<exchange_rate_object, network, &exchange_rate_object::network>

>

>

>;

// Version with timestamp

struct by_network_valid_from;

using exchange_rate_multi_index_type = multi_index_container<

exchange_rate_object,

indexed_by<

ordered_unique< tag<by_id>,

member<object, object_id_type, &object::id>

>,

ordered_unique< tag<by_network_valid_from>,

composite_key<exchange_rate_object,

member<exchange_rate_object, network, &exchange_rate_object::network>,

member<exchange_rate_object, time_point_sec, &exchange_rate_object::valid_from>,

>

>

>

>;

  • Exchange rate list should be indexed at least by network and valid_from fields, so a composite key is required.

  • Exchange rate list will be queried with parameters network and timestamp, and the query should return exchange rate valid at a date and time from the timestamp. Exchange rate is valid from the latest timestamp less than the timestamp parameter. E.g. we have the following exchange rate list:

    BTC, 2019-11-20 00:00:00, 100000000, X BTC, 2019-11-25 00:00:00, 100000000, X1

    If we query the index with (network::bitcoin, 2019-11-23), query should return value X, since that exchange rate is valid in the period of [2019-11-20 00:00:00 to 2019-11-24 23:59:59]

    Read Boost MultiIndex docs, to learn about all the ways this is possible to do: https://www.boost.org/doc/libs/1_67_0/libs/multi_index/doc/tutorial/basics.html#special_lookup

Exchange rate create operations:

struct exchange_rate_create_operation : public base_operation

{

uint32_t exchange_rate_id; // Primary key

network network; // Network managing the currency

int64_t exchange_from; // Network native currency amount

int64_t exchange_to; // Peerplays asset amount (pBTC)

void validate()const;

};

// Version with timestamp

struct exchange_rate_create_operation : public base_operation

{

uint32_t exchange_rate_id; // Primary key

network network; // Network managing the currency

time_point_sec valid_from; // Starting date when exchange rate becomes valid

int64_t exchange_from; // Network native currency amount

int64_t exchange_to; // Peerplays asset amount (pBTC)

void validate()const;

};

Validation should check that the item is not duplicated. Eventually, it can check exchange_from precision, since they are known in advance.

Exchange rate update operations:

struct exchange_rate_update_operation : public base_operation

{

uint32_t exchange_rate_id; // Primary key

network network; // Network managing the currency

int64_t exchange_from; // Network native currency amount

int64_t exchange_to; // Peerplays asset amount (pBTC)

void validate()const;

};

// Version with timestamp

struct exchange_rate_update_operation : public base_operation

{

uint32_t exchange_rate_id; // Primary key

network network; // Network managing the currency

time_point_sec valid_from; // Starting date when exchange rate becomes valid

int64_t exchange_from; // Network native currency amount

int64_t exchange_to; // Peerplays asset amount (pBTC)

void validate()const;

};

Validation should check that the item with the given exchange_rate_id exists in the list.

Exchange rate list delete operation:

// Same for both versions

struct exchange_rate_delete_operation : public base_operation

{

uint32_t exchange_rate_id; // Primary key

void validate()const;

};

Validation should check that the item with the given exchange_rate_id exists in the list.

Appropriate evaluators must be implemented too.

Logo
Logo

NFT Minting

A guide for creating NFTs from start to finish.

1. Creating Non-Fungible Tokens (NFTs)

Creating NFTs in Peerplays is a two step process.

First, the metadata must be created for the NFT. This can be thought of like a template from which NFTs can be constructed. The account which owns the NFT metadata is the account with the rights to mint (create) the actual NFTs based on that metadata. The metadata is used to set certain basic permissions for the NFT, revenue sharing options, and the NFT identity information (name, symbol, and a URI).

Then using the metadata, NFTs can be minted into existence by the metadata owner. Once the NFTs are minted, they can be transferred, sold, auctioned, or otherwise used for their intended purpose as the permissions in the metadata allow.

2. NFT Metadata

2.1. nft_metadata_create

This function creates a new NFT metadata object. It can be created with or without a set of permissions. See the guide on permissions for details about creating resource permissions.

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::nft_metadata_create(
  string owner_account_id_or_name,
  string name,
  string symbol,
  string base_uri,
  optional<string> revenue_partner,
  optional<uint16_t> revenue_split,
  bool is_transferable,
  bool is_sellable,
  optional<account_role_id_type> role_id,
  bool broadcast)

The basic structure of the nft_metadata_create function looks like this:

When using the cli_wallet...
nft_metadata_create <owner_account_id_or_name> <name> <symbol> <base_uri> <revenue_partner> <revenue_split> <is_transferable> <is_sellable> <role_id> true

Parameters

name

data type

description

owner_account_id_or_name

string

The name or id of the account who is creating the metadata.

name

string

The name of the NFTs created from this metadata.

symbol

string

The symbol of the NFTs created from this metadata.

base_uri

string

The URI of the NFT. This could be a website link, an API call, something on IPFS, some other unique identifier, etc.

revenue_partner

string (optional)

The account name of the revenue partner. Whenever the minted NFT is sold in the marketplace a split of the selling price goes to the revenue partner. This can be the metadata owner.

revenue_split

uint16_t (optional)

The amount of the selling price that goes to the revenue partner. 10000 = 100%, 100 = 1%, 1 = 0.01%

is_transferable

bool

Specifies if the minted NFTs can be transferred by the owner of the NFT to other accounts.

is_sellable

bool

Specifies if the minted NFTs can be sold in the marketplace.

role_id

account_role_id_type (optional)

The resource permissions specifying the whitelisted accounts among which the NFTs can either be transferred or sold on the marketplace.

broadcast

bool

true or false, whether or not you want to broadcast the transaction to the network.

Example Call Without Permissions

nft_metadata_create account01 "AVALON NAME" "AVALON SYMBOL" "avalonmeta.com" account02 150 false true null true

In the example above:

  • account01 is the owner account of the metadata.

  • "AVALON NAME" is the name of the NFTs created from this NFT metadata.

  • "AVALON SYMBOL" is the symbol of the NFTs created from this NFT metadata. The symbol is reserved for future use.

  • "avalonmeta.com" is the URI of the NFTs.

  • account02 is the revenue partner.

  • 150 is the revenue_split that will be shared with the revenue_partner. In this case, 1.5%.

  • false, is_transferable specifies the minted NFTs cannot be transferred by the owner of the NFT to other accounts.

  • true, is_sellable specifies minted NFTs can be sold in the marketplace.

  • null, role_id is not set.

  • true, This transaction will be in the upcoming block on the chain.

Example Call With Permissions

First we create the permission:

create_account_role account01 "Avalon Permissions1" "Permission Metadata" [88,89,90,95] [1.2.40, 1.2.41] "2020-11-04T13:43:39" true

In the above function...

  • account01 is the owner of the permission being created which can be attached to NFT metadata.

  • "Avalon Permissions1" is the name of the resource permission being created.

  • "Permission Metadata" is the metadata, can be a JSON object as well.

  • [88,89,90,95] is the list of operations this permission whitelists for accounts.

    • 88 - List Offer operation in marketplace

    • 89 - Bid operation in marketplace

    • 90 - Cancel Offer operation in marketplace

    • 95 - Safe transfer from owner to another NFT

    • IDs are available here.

  • [1.2.40, 1.2.41] List of accounts whitelisted for the above operations. Offer, bid and transfer operations can only be among the whitelisted accounts.

  • "2020-11-04T13:43:39" Expiry date of the permission

  • true broadcast, keep it true to include the transaction in upcoming block.

Then we create the metadata with the above permission:

nft_metadata_create account01 "AVALON NAME" "AVALON SYMBOL" "avalonmeta.com" account02 150 false true 1.32.0 true

This example is just like the previous, except this time we include 1.32.0, the role_id, to attach permissions to all the NFTs created from this metadata.

2.2. nft_metadata_update

This function updates an existing NFT metadata object.

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::nft_metadata_update(
  string owner_account_id_or_name,
  nft_metadata_id_type nft_metadata_id,
  optional<string> name,
  optional<string> symbol,
  optional<string> base_uri,
  optional<string> revenue_partner,
  optional<uint16_t> revenue_split,
  optional<bool> is_transferable,
  optional<bool> is_sellable,
  optional<account_role_id_type> role_id,
  bool broadcast)

The basic structure of the nft_metadata_update function looks like this:

When using the cli_wallet...
nft_metadata_update <owner_account_id_or_name> <nft_metadata_id> <name> <symbol> <base_uri> <revenue_partner> <revenue_split> <is_transferable> <is_sellable> <role_id> true

Parameters

name

data type

description

owner_account_id_or_name

string

The name or id of the account who owns the metadata this NFT is based on.

nft_metadata_id

nft_metadata_id_type

The ID of the metadata you want to update.

name

string (optional)

A new name for the NFT.

symbol

string (optional)

A new symbol for the NFT.

base_uri

string (optional)

A new URI of the NFT.

revenue_partner

string (optional)

A new revenue partner account name or id.

revenue_split

uint16_t (optional)

A new revenue split amount.

is_transferable

bool (optional)

Whether or not the minted NFTs are transferable.

is_sellable

bool (optional)

Whether or not the minted NFTs are sellable in the marketplace.

role_id

account_role_id_type

A new set of resource permissions.

broadcast

bool

true or false, whether or not you want to broadcast the transaction to the network.

Example Call

nft_metadata_update account01 1.30.1 sknft01 sknft01 sknft01 null null true true true

3. Minting NFTs

3.1. nft_create

This function mints an NFT based on the metadata. NFTs are always minted by the owner of the metadata object the NFTs are based on. The fees associated with minting an NFT is just the transaction fee + storage fee which are both collected in core PPY token. After an NFT has been minted it can be sold on the marketplace for any token of the NFT owner’s choice.

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::nft_create(
  string metadata_owner_account_id_or_name,
  nft_metadata_id_type metadata_id,
  string owner_account_id_or_name,
  string approved_account_id_or_name,
  string token_uri,
  bool broadcast)

The basic structure of the nft_create function looks like this:

When using the cli_wallet...
nft_create <metadata_owner_account_id_or_name> <metadata_id> <owner_account_id_or_name> <approved_account_id_or_name> <token_uri> true

Parameters

name

data type

description

metadata_owner_account_id_or_name

string

The name or id of the account who owns the metadata this NFT is based on.

metadata_id

nft_metadata_id_type

The NFT metadata object ID to base this NFT on. (Currently this works on the "best guess" method by doing get_object 1.30.0, 1.30.1, 1.30.2... and so on. In the future a new cli command will be introduced that can list all the metadata objects by owner account.)

owner_account_id_or_name

string

The owner of the freshly minted NFT. As the owner of the metadata, you can mint NFTs directly into someone elses account!

approved_account_id_or_name

string

The approved account of the NFT, can be the owner as well.

token_uri

string

The URI of the NFT. This could be a website link, an API call, something on IPFS, some other unique identifier, etc.

broadcast

bool

true or false, whether or not you want to broadcast the transaction to the network.

Example Call

nft_create account01 1.30.0 account02 account02 "AVALON NFT URI" true

In the example above:

  • account01 is the owner account of the metadata.

  • 1.30.0 is the ID of the metadata object.

  • account02 is the owner of the minted NFT.

  • account02 is the approved account of the minted NFT.

  • AVALON NFT URL is the URI that has additional information about this NFT.

  • true, This transaction will be in the upcoming block on the chain.

4. Sending NFTs

4.1. nft_transfer_from (nft_safe_transfer_from)

These functions are used to transfer NFTs from one account to another, if allowed. The difference between the two is that the safe transfer includes a string parameter which can be used to send along some metadata (or a memo) with the NFT. Otherwise, they are the same.

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::nft_transfer_from(
  string operator_account_id_or_name,
  string from_account_id_or_name,
  string to_account_id_or_name,
  nft_id_type token_id,
  bool broadcast)

Or...

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::nft_safe_transfer_from(
  string operator_account_id_or_name,
  string from_account_id_or_name,
  string to_account_id_or_name,
  nft_id_type token_id,
  string data,
  bool broadcast)

The basic structure of the nft_transfer_from and nft_safe_transfer_from function looks like this:

When using the cli_wallet...
nft_transfer_from <operator_account_id_or_name> <from_account_id_or_name> <to_account_id_or_name> <token_id> true

nft_safe_transfer_from <operator_account_id_or_name> <from_account_id_or_name> <to_account_id_or_name> <token_id> <data> true

Parameters

name

data type

description

operator_account_id_or_name

string

The operator or owner account.

from_account_id_or_name

string

The account sending the NFT.

to_account_id_or_name

string

The account receiving the NFT.

token_id

nft_id_type

The ID of the NFT.

data

string

Only for nft_safe_transfer_from, you can include more metadata in the transfer with this field.

broadcast

bool

true or false, whether or not you want to broadcast the transaction to the network.

Example Call

nft_safe_transfer_from account02 account02 account03 1.31.0 "Enjoy my NFT" true

In the example above:

  • account02 is the owner or operator account.

  • account02 is sending the NFT.

  • account03 is receiving the NFT.

  • 1.31.0 is the ID of the NFT.

  • "Enjoy my NFT" is the metadata of the transfer.

  • true, This transaction will be in the upcoming block on the chain.

5. Related Documents

The functions listed in this guide will cost transaction fees. To calculate how much PPY you'll need to make these transactions and meet your development goals, please see the Calculating Costs guide.

Governance

Governance

create_committee_member

Creates a committee_member object owned by the given account.

An account can have at most one committee_member object.

signed_transaction graphene::wallet::wallet_api::create_committee_member(
    string owner_account, 
    string url, 
    bool broadcast = false)
  • owner_account: the name or id of the account which is creating the committee_member

  • url: a URL to include in the committee_member record in the blockchain. Clients may display this when showing a list of committee_members. May be blank.

  • broadcast: true to broadcast the transaction on the network

The signed transaction registering a committee_member

get_witness

Returns information about the given witness.

witness_object graphene::wallet::wallet_api::get_witness(
    string owner_account)
  • owner_account: the name or id of the witness account owner, or the id of the witness

The information about the witness stored in the block chain.

get_committee_member

Returns information about the given committee_member.

committee_member_object graphene::wallet::wallet_api::get_committee_member(
    string owner_account)
  • owner_account: the name or id of the committee_member account owner, or the id of the committee_member.

The information about the committee_member stored in the block chain

list_witnesses

Lists all Witnesses registered in the blockchain. This returns a list of all account names that own Witnesses, and the associated witness id, sorted by name. This lists Witnesses whether they are currently voted in or not.

Use the lowerbound and limit parameters to page through the list. To retrieve all Witness's, start by setting lowerbound to the empty string "", and then each iteration, pass the last witness name returned as the lowerbound for the next list_witnesss() call.

map<string, witness_id_type> graphene::wallet::wallet_api::list_witnesses(
    const string &lowerbound, 
    uint32_t limit)
  • lowerbound: the name of the first Witness to return. If the named Witness does not exist, the list will start at the witness that comes after lowerbound

  • limit: the maximum number of Witness's to return (max: 1000)

A list of Witness's mapping witness names to witness ids

list_committee_members

Lists all committee_members registered in the blockchain. This returns a list of all account names that own committee_members, and the associated committee_member id, sorted by name. This lists committee_members whether they are currently voted in or not.

Use the lowerbound and limit parameters to page through the list. To retrieve all committee_members, start by setting lowerbound to the empty string "", and then each iteration, pass the last committee_member name returned as the lowerbound for the next list_committee_members() call.

map<string, committee_member_id_type> graphene::wallet::wallet_api::list_committee_members(
    const string &lowerbound, 
    uint32_t limit)
  • lowerbound: the name of the first committee_member to return. If the named committee_member does not exist, the list will start at the committee_member that comes after lowerbound

  • limit: the maximum number of committee_members to return (max: 1000)

A list of committee_members mapping committee_member names to committee_member ids

create_witness

Creates a witness object owned by the given account.

An account can have at most one witness object.

signed_transaction graphene::wallet::wallet_api::create_witness(
    string owner_account, 
    string url, 
    bool broadcast = false)
  • owner_account: the name or id of the account which is creating the witness

  • url: a URL to include in the witness record in the blockchain. Clients may display this when showing a list of witnesses. May be blank.

  • broadcast: true to broadcast the transaction on the network

The signed transaction registering a witness

update_witness

Update a witness object owned by the given account.

signed_transaction graphene::wallet::wallet_api::update_witness(
    string witness_name, 
    string url, 
    string block_signing_key, 
    bool broadcast = false)
  • witness_name: The name of the witness’s owner account. Also accepts the ID of the owner account or the ID of the witness.

  • url: Same as for create_witness. The empty string makes it remain the same.

  • block_signing_key: The new block signing public key. The empty string makes it remain the same.

  • broadcast: true if you wish to broadcast the transaction.

The signed transaction

create_worker

Create a worker object.

signed_transaction graphene::wallet::wallet_api::create_worker(
    string owner_account, 
    time_point_sec work_begin_date, 
    time_point_sec work_end_date, 
    share_type daily_pay, 
    string name, string url, 
    variant worker_settings, 
    bool broadcast = false)
  • owner_account: The account which owns the worker and will be paid

  • work_begin_date: When the work begins

  • work_end_date: When the work ends

  • daily_pay: Amount of pay per day (NOT per maint interval)

  • name: Any text

  • url: Any text

  • worker_settings: {“type” : “burn”|”refund”|”vesting”, “pay_vesting_period_days” : x}

  • broadcast: true if you wish to broadcast the transaction.

The signed transaction

update_worker_votes

Update your votes for workers.

signed_transaction graphene::wallet::wallet_api::update_worker_votes(
    string account, 
    worker_vote_delta delta,
    bool broadcast = false)
  • account: The account which will pay the fee and update votes.

  • delta: {“vote_for” : […], “vote_against” : […], “vote_abstain” : […]}

  • broadcast: true if you wish to broadcast the transaction.

The signed transaction

vote_for_committee_member

Vote for a given committee_member.

An account can publish a list of all committee_members they approve of. This command allows you to add or remove committee_members from this list. Each account’s vote is weighted according to the number of shares of the core asset owned by that account at the time the votes are tallied.

Note: You can't vote against a committee_member, you can only vote for the committee_member or not vote for the committee_member.

signed_transaction graphene::wallet::wallet_api::vote_for_committee_member(
    string voting_account, 
    string committee_member, 
    bool approve, 
    bool broadcast = false)
  • voting_account: the name or id of the account who is voting with their shares

  • committee_member: the name or id of the committee_member’ owner account

  • approve: true if you wish to vote in favour of that committee_member, false to remove your vote in favour of that committee_member

  • broadcast: true if you wish to broadcast the transaction

The signed transaction changing your vote for the given committee_member.

vote_for_witness

Vote for a given witness.

An account can publish a list of all witnesses they approve of. This command allows you to add or remove witnesses from this list. Each account’s vote is weighted according to the number of shares of the core asset owned by that account at the time the votes are tallied.

Note: You can't vote against a witness, you can only vote for the witness or not vote for the witness.

signed_transaction graphene::wallet::wallet_api::vote_for_witness(
    string voting_account, 
    string witness, 
    bool approve, 
    bool broadcast = false)
  • voting_account: the name or id of the account who is voting with their shares

  • witness: the name or id of the witness’ owner account

  • approve: true if you wish to vote in favour of that witness, false to remove your vote in favour of that witness

  • broadcast: true if you wish to broadcast the transaction

The signed transaction changing your vote for the given witness

set_voting_proxy

Set the voting proxy for an account.

If a user does not wish to take an active part in voting, they can choose to allow another account to vote their stake.

Setting a vote proxy does not remove your previous votes from the blockchain, they remain there but are ignored. If you later null out your vote proxy, your previous votes will take effect again.

This setting can be changed at any time.

signed_transaction graphene::wallet::wallet_api::set_voting_proxy(
    string account_to_modify, 
    optional<string> voting_account, 
    bool broadcast = false)
  • account_to_modify: the name or id of the account to update

  • voting_account: the name or id of an account authorized to vote account_to_modify’s shares, or null to vote your own shares

  • broadcast: true if you wish to broadcast the transaction

The signed transaction changing your vote proxy settings

set_desired_witness_and_committee_member_count

Set your vote for the number of witnesses and committee_members in the system.

Each account can voice their opinion on how many committee_members and how many witnesses there should be in the active committee_member/active witness list. These are independent of each other. You must vote your approval of at least as many committee_members or witnesses as you claim there should be (you can’t say that there should be 20 committee_members but only vote for 10).

There are maximum values for each set in the blockchain parameters (currently defaulting to 1001).

This setting can be changed at any time. If your account has a voting proxy set, your preferences will be ignored.

signed_transaction graphene::wallet::wallet_api::set_desired_witness_and_committee_member_count(
    string account_to_modify, 
    uint16_t desired_number_of_witnesses, 
    uint16_t desired_number_of_committee_members, 
    bool broadcast = false)
  • account_to_modify: the name or id of the account to update

  • desired_number_of_witnesses: desired number of active witnesses

  • desired_number_of_committee_members: desired number of active committee members

  • broadcast: true if you wish to broadcast the transaction

The signed transaction changing your vote proxy settings

propose_parameter_change

Creates a transaction to propose a parameter change.

Multiple parameters can be specified if an atomic change is desired.

signed_transaction graphene::wallet::wallet_api::propose_parameter_change(
    const string &proposing_account, 
    fc::time_point_sec expiration_time, 
    const variant_object &changed_values, 
    bool broadcast = false)
  • proposing_account: The account paying the fee to propose the tx

  • expiration_time: Timestamp specifying when the proposal will either take effect or expire.

  • changed_values: The values to change; all other chain parameters are filled in with default values

  • broadcast: true if you wish to broadcast the transaction

The signed version of the transaction

propose_fee_change

Propose a fee change.

signed_transaction graphene::wallet::wallet_api::propose_fee_change(
    const string &proposing_account, 
    fc::time_point_sec expiration_time, 
    const variant_object &changed_values, 
    bool broadcast = false)
  • proposing_account: The account paying the fee to propose the tx

  • expiration_time: Timestamp specifying when the proposal will either take effect or expire.

  • changed_values: Map of operation type to new fee. Operations may be specified by name or ID. The “scale” key changes the scale. All other operations will maintain current values.

  • broadcast: true if you wish to broadcast the transaction

The signed version of the transaction

Logo
Logo

creation of a multi-sig bitcoin address lld

1. Purpose

The purpose of this document is to provide a low-level design for the creation of a multi-signature bitcoin address.

2. Scope

The design requirement listed in this document will be limited to the creation of a multi-signature address managed by SONs in the Peerplays network.

The document will also outline the types of transactions present in the bitcoin network.

The document will also outline the scripting mechanism that locks/unlocks the transactions in the bitcoin network.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Types of Transactions

4.1 P2PK

They are known as Pay to PubKey transactions.

They are an older way of sending bitcoins to a single address.

“OP_DATA_65 OP_CHECKSIG” and “OP_DATA_33 OP_CHECKSIG” is the format of the Pkscript used in these types of transactions.

The public key of the receiver of bitcoin is specified in the locking Pkscript.

Unlocking sigscript should contain the signature with the private key of the spender/receiver.

4.2 P2PKH

They are known as Pay to PubKey Hash transactions.

They are the standard and popular way of sending bitcoins to a single address.

“OP_DUP OP_HASH160 OP_DATA_20 OP_EQUALVERIFY OP_CHECKSIG” is the format of the Pkscript in these types of transactions.

The hash160 of the public key of the receiver is specified in the locking script.

4.3 P2SH

They are known as Pay to Script Hash transactions.

They are generally used to send bitcoins to multi-sig addresses.

“OP_HASH160 OP_DATA_20 OP_EQUAL” is the format of the Pkscript in these types of transactions.

The OP_DATA_20 opcode is followed by a 20 byte hash of the P2SH RedeemScript which can be provided by the receiver in a future transaction.

It moves the responsibility for supplying the conditions to redeem a transaction from the creator of the transaction to the receiver.

4.4 P2WPKH

They are known as Pay To Witness Public Key Hash transactions.

They are introduced as part of the SegWit improvements to the bitcoin network.

“0 <20-byte-PublicKeyHash>” is the format of the Pkscript in these types of transactions.

The ScriptSig/Unlocking-script is empty.

“<Signature> <PublicKey>” is the format of the witness field.

Verification goes as follows,

  • Check that the witness contains exactly two items.

  • Verify that HASH160 of the witness' public key is equal to the one present in the witness program.

  • Verify the signature as <Signature> <PublicKey> OP_CHECKSIG.

There is no OP_CHECKSIG operand in neither PKscript/scriptPubKey nor witness, it is implicit by the definition of P2WPKH.

4.5 P2WSH

They are known as Pay To Witness Script Hash transactions.

They are introduced as part of the SegWit improvements to the bitcoin network.

“0 <32-byte-redeemScriptHash” is the format of the Pkscript in these types of transactions.

The ScriptSig/Unlocking-script is empty.

“<witness items> <redeemScript>” is the format of the witness field.

Verification goes as follows,

  • The last item in the witness is popped off, hashed with SHA256, compared against the 32-byte-hash in Pkscript/scriptPubKey.

  • Then the script is executed with the remaining data from the witness.

4.6 Others

There are nested types of transactions as well like P2WSH nested in P2SH and P2WPKH nested in P2SH.

These are out of the scope of this document and can be found online.

5. Bitcoin Scripting

Bitcoin uses a scripting system for transactions.

The scripts are simple, stack-based and processes from left to right.

They are not Turing-complete and don’t have loops.

A script is essentially a list of instructions recorded with each transaction that describes how the next person wanting to spend the Bitcoins being transferred can gain access to them.

The script for a typical Bitcoin transfer to a destination Bitcoin address simply encumbers future spending of the bitcoins with two things: the spender must provide

  1. a public key that, when hashed, yields destination address embedded in the script, and

  2. a signature to prove ownership of the private key corresponding to the public key just provided.

As it is stack-based, a transaction is valid if nothing in the combined script (i.e. Pkscript+Scriptsig) triggers failure and the top stack item is True (non-zero) when the script exits.

5.1 P2PKH Script Execution

Following is the script for a Typical P2PKH transaction,

scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

scriptSig: <sig> <pubKey>

Note: scriptSig is in the input of the spending transaction and scriptPubKey is in the output of the previously unspent i.e. "available" transaction.

5.2 P2SH Script Execution

P2SH script is a bit different from a typical P2PKH transaction script.

Following is an example of a 2-of-3 multisig address transaction,

scriptPubKey: OP_HASH160 <redeemScript_hash> OP_EQUAL

scriptSig: 0 <sig1> <sig2> <redeemScript>

redeemScript: 2 <pub-key1> <pub-key2> <pub-key3> 3 OP_CHECKMULTISIG

The flow of execution is something like this for P2SH,

  1. Execute scriptSig which creates stack

  2. Copy stack to stackCopy

  3. Execute scriptPubKey using stack

  4. If P2SH, replace stack with stackCopy

  5. If P2SH, Pop top item off of stack and execute as redeemScript using stack.

Essentially, scriptPubKey is executed and it checks if the hash of redeemScript is that of the hash given.

Then, redeemScript is executed with the required signatures in front.

Execution for both P2WSH and P2WPKH is similar to the related non-segwit variants except that scriptSig is empty and we keep the data in witness script.

5.3 A bit about OP_CHECKMULTISIG

This crypto opcode is used to verify the signature for m-of-n multisig address transactions.

It handles up to 20-of-20 multisig address transactions.

It has a bug in that it tries to pop m+n+3 elements off the stack instead of m+n+2 elements.

That’s why a zero (0) is added at the front of scriptSig/Witness.

A high-level pseudo-code looks like this,

  1. Pop n off of the stack (number of public keys)

  2. Pop n public keys off of the stack.

  3. Pop m off of the stack (number of required signatures)

  4. Pop m signatures off of the stack.

  5. Pop one more element off of the stack, and ignore it. (This is a bug, but it can't be fixed because this is consensus-critical code.)

  6. Loop through all of the public keys, starting with the keys at the top of the stack.

    1. For each public key, check a single signature.

    2. For the first public key checked, start with the signature closest to the top of the stack.

    3. If it fails to verify, go to the next public key and check the same signature.

    4. If it succeeds, go to the next public key with the next signature.

Note that the signatures need to be in the same order as the key's that they're signing for.

  1. If all of the signatures succeeded with one of the keys, CHECKMULTISIG returns 1, otherwise 0.

Essentially, the key takeaways are,

  • All the signatures should be in the same order as that of public keys.

  • All of the signatures provided should match with at least one of the public keys.

5.4 Why can’t we use OP_CHECKMULTISIG?

We can’t use the opcode because it assumes by default all signatures/public-keys have the same weight.

It just checks if we have m valid signatures out of n possible public keys.

But in the SON’s case, we have weights attached to each SON based on the votes a SON receives.

We have to in SON’s case, add up the weights of each SON signature and check if we have enough total weight to publish a transaction on the bitcoin network.

So we can’t use a simple OP_CHECKMULTISIG in our case; we have to come up with a custom script.

6. Custom Bitcoin Script for SONs

We can go with P2WSH or P2SH for our wallet addresses.

But P2WSH is preferred as it is the latest, efficient and backward compatible.

For P2WSH, we have to provide witness script and a hash of our redeemScript to depositor/sender.

witness = “<witness items> <redeemScript>”

redeemScript can be as follows,

<pubkey1> OP_CHECKSIG

OP_IF

<voting_weight1>

OP_ELSE

0

OP_ENDIF

OP_SWAP

<pubkey2> OP_CHECKSIG

OP_IF

<voting_weight2>

OP_ADD

OP_ENDIF

...

OP_SWAP

<pubkeyN-1> OP_CHECKSIG

OP_IF

<voting_weightN-1>

OP_ADD

OP_ENDIF

OP_SWAP

<pubkeyN> OP_CHECKSIG

OP_IF

<voting_weightN>

OP_ADD

OP_ENDIF

<two_thirds_of_total_voting_weight>

OP_GREATERTHAN

witness items is a list of SON signatures in the ascending order of their voting weights assuming the redeem script has public keys of SONs in descending order.

We will have to order the SON signatures in the reverse order of how public keys are ordered in redeem script.

Even if any SON signature is not available, we have to add a dummy signature in order to execute the script properly.

7. Design Changes

8. Change of scenario of SONs

8.1 Change of SON Weights

SON weights are calculated based on the votes received.

This calculation is done at the end of the maintenance interval.

Of the active SONs(15) selected after the maintenance interval, we can treat their respective weights as total_votes from each son_object.

Eg. Take 3 SONs,

SON1 weight → total_votes = 10

SON2 weight → total_votes = 20

SON3 weight → total_votes = 30

Total weight = 60

Minimum required weight to unlock the transaction = 2/3 * 60 + 1 = 41

If the rankings remain the same but the weights change, we can’t use the same script as before because weights in the script are invalid now.

If the rankings change but the same SONs are active, we still can’t use the same script because weights in the script are invalid now.

8.2 SON Down

If any of the SONs are down and the current total weight is greater than or equal to 67% of the actual total weight of SONs at the start of the maintenance interval, we can still continue to sign transactions hoping that we hit the required limit in the script.

Eg. Take 5 SONs,

SON1 weight → 20

SON2 weight → 20

SON3 weight → 20

SON4 weight → 20

SON5 weight → 20

Total Weight when address is created → 100

SON5 went down abruptly,

Current total weight → 80 ( >= 67 )

So we can still continue to work with the existing set of addresses till the next maintenance.

Now, SON4 also went down abruptly,

Current total weight → 60 ( < 67 )

Now we are below the required minimum weight in the script, so we can’t successfully sign any transactions.

More down scenarios are captured

Stack

Script

Description

Empty.

<sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

scriptSig and scriptPubKey are combined.

<sig> <pubKey>

OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Constants are added to the stack.

<sig> <pubKey> <pubKey>

OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Top stack item is duplicated.

<sig> <pubKey> <pubHashA>

<pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Top stack item is hashed.

<sig> <pubKey> <pubHashA> <pubKeyHash>

OP_EQUALVERIFY OP_CHECKSIG

Constant added.

<sig> <pubKey>

OP_CHECKSIG

Equality is checked between the top two stack items.

true

Empty.

Signature is checked for the top two stack items.

here.
Logo
Logo
Logo

Quick joining GLADIATOR

Setup SONs and join GLADIATOR public TESTNET

This is a quick document which assumes that the user has experience in setting up various Graphene blockchains before. The following link can be a good refresher: https://community.peerplays.tech/witnesses/becoming-a-witness

In this document the executables are downloaded for the Gitlab CI-CD pipeline

1. Prepare the server

The following dependencies are necessary for a clean Ubuntu 18.04 LTS

sudo apt-get install autoconf bash build-essential ca-certificates cmake \
     doxygen git graphviz libbz2-dev libcurl4-openssl-dev libncurses-dev \
     libreadline-dev libssl-dev libtool libzmq3-dev locales ntp pkg-config \
     wget

2. Download SON executable

Go to https://gitlab.com/PBSA/peerplays/-/jobs and find the job ID for the build you want to use. Build should have the following properties

  • Job: features/SONs-base

  • Stage: build

  • Name: build

Example of such a job has ID 467332251:

To download executables, click Download button on the right side of the Job page, or execute the following command:

wget --content-disposition --show-progress\
 https://gitlab.com/PBSA/peerplays/-/jobs/538784707/artifacts/download

To unpack executables in current folder:

unzip -j artifacts.zip build/programs/cli_wallet/cli_wallet -d ./
unzip -j artifacts.zip build/programs/witness_node/witness_node -d ./

Execute the witness_node binary which will create the necessary files and folders under witness_node_data_dir

./witness_node

Stop the node (CTRL + c ) and edit config.ini to configure the node.

Connecting to PBSA's Gladiator Testnet

Inside config.ini, set the seed-nodes to:

seed-nodes=["96.46.49.1:9777", "96.46.49.2:9777", "96.46.49.3:9777", "96.46.49.4:9777", "96.46.49.5:9777", "96.46.49.6:9777", "96.46.49.7:9777", "96.46.49.8:9777", "96.46.49.9:9777", "96.46.49.10:9777", "96.46.49.11:9777", "96.46.49.12:9777", "96.46.49.13:9777", "96.46.49.14:9777", "96.46.49.15:9777", "96.46.49.16:9777"]

In order to sync with PBSA's Gladiator Testnet, the genesis file must be exactly the same as used by the witness nodes. This file can be downloaded here: https://drive.google.com/file/d/1YmDbwUB-5D5vGzc9vYEva8yLkTkwva8r/view?usp=sharing

wget --no-check-certificate 'https://docs.google.com/uc?export=download&id=1YmDbwUB-5D5vGzc9vYEva8yLkTkwva8r' -O SONs_genesis.json

Move the genesis.json file to the root of the project directory alongside the witness_node binary.

Inside config.ini, specify the genesis.json

genesis-json = genesis.json

Start the witness_node and the blocks should start syncing.

./witness_node --gensis-file SONs_genesis.json

If blocks have already been seeded during the initial startup, it may be necessary to reset the blockchain and p2p directories. Removing them is fine for this case.

rm -rf witness_node_data_dir/blockchain
rm -rf witness_node_data_dir/p2p

At this point you will be able download a copy of the blockchain. Additional steps are required to run the cli_wallet and also become a SON.

SON configuration

Prerequisites

  • Your node is up and running and synced with the network.

  • You have access to a bitcoin node, with RPC and ZMQ notifications enabled

  • You have access to shared wallet used by all SONs (prerelease requirement only)

Configuration files

SON plugin is controlled by following parameters

peerplays_sidechain plugin. <no description>
Options:
  --son-id arg                          ID of SON controlled by this node (e.g.
                                        "1.27.5", quotes are required)
  --son-ids arg                         IDs of multiple SONs controlled by this
                                        node (e.g. ["1.27.5", "1.27.6"], quotes
                                        are required)
  --peerplays-private-key arg (=["TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"])
                                        Tuple of [PublicKey, WIF private key] 
                                        (may specify multiple times)
  --bitcoin-node-ip arg (=99.79.189.95) IP address of Bitcoin node
  --bitcoin-node-zmq-port arg (=11111)  ZMQ port of Bitcoin node
  --bitcoin-node-rpc-port arg (=22222)  RPC port of Bitcoin node
  --bitcoin-node-rpc-user arg (=1)      Bitcoin RPC user
  --bitcoin-node-rpc-password arg (=1)  Bitcoin RPC password
  --bitcoin-wallet arg                  Bitcoin wallet
  --bitcoin-wallet-password arg         Bitcoin wallet password
  --bitcoin-private-key arg (=["02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772","cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"])
                                        Tuple of [Bitcoin public key, Bitcoin 
                                        private key] (may specify multiple 
                                        times)

These parameters are available from both command line and config file:

Edit add the following to your config.ini file

# ==============================================================================
# peerplays_sidechain plugin options
# ==============================================================================

# ID of SON controlled by this node (e.g. "1.27.5", quotes are required)
son-id = "1.27.0"

# IDs of multiple SONs controlled by this node (e.g. ["1.27.5", "1.27.6"], quotes are required)
son-ids = []

# Tuple of [PublicKey, WIF private key]
peerplays-private-key = ["TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]

# IP address of Bitcoin node
bitcoin-node-ip = 99.79.189.95

# ZMQ port of Bitcoin node
bitcoin-node-zmq-port = 11111

# RPC port of Bitcoin node
bitcoin-node-rpc-port = 22222

# Bitcoin RPC user
bitcoin-node-rpc-user = 1

# Bitcoin RPC password
bitcoin-node-rpc-password = 1

# Bitcoin wallet
bitcoin-wallet = son-wallet

# Bitcoin wallet password
bitcoin-wallet-password = 9da115c9fa6fe7fd09390841ac91aee4

# Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)
bitcoin-private-key = ["02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772","cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"]

Edit the config file and add the RPC port

# Endpoint for websocket RPC to listen on
rpc-endpoint = 127.0.0.1:8090

Becoming a SON

Becoming a SON is very similar to becoming a witness. You will need:

  • Active user account, upgraded to lifetime member, which will be the owner of SON account

  • Create two vesting balances (types son and normal) of 50 core assets, and get its IDs

  • Create Bitcoin address for SON account in shared SON wallet

  • Create SON account, and get its ID

  • Set the signing key for a son account (usually, its a signing key of owner account)

  • Set the bitcoin address as a sidechain address for a SON account

  • Update your config file with values obtained in previous steps, and restart the witness with peerplays_sidechain plugin enabled

Example:

# ================================================================================
# Active user account, upgraded to lifetime member, which will be the owner of SON account
unlocked >>> get_account account07
get_account account07
{
  "id": "1.2.58",
  "membership_expiration_date": "2106-02-07T06:28:15",
  "registrar": "1.2.58",
  "referrer": "1.2.58",
  "lifetime_referrer": "1.2.58",
  "network_fee_percentage": 2000,
  "lifetime_referrer_fee_percentage": 8000,
  "referrer_rewards_percentage": 0,
  "name": "account07",
  "owner": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [[
        "TEST86obxk1fqh8cmDkRdgyVkzHtcmqcByva7tk9DYAjCpLPkxqeCC",
        1
      ]
    ],
    "address_auths": []
  },
  "active": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [[
        "TEST7SUmjftH3jL5L1YCTdMo1hk5qpZrhbo4MW6N2wWyQpjXkT7ByB",
        1
      ]
    ],
    "address_auths": []
  },
...
}
# ================================================================================

# ================================================================================
# Create two vesting balances (types son and normal) of 50 core assets, and get its IDs
unlocked >>> create_vesting_balance account07 50 TEST son true
create_vesting_balance account07 50 TEST son true
{
  "ref_block_num": 3977,
  "ref_block_prefix": 145563165,
  "expiration": "2020-03-13T17:08:45",
  "operations": [[
      32,{
...
}

unlocked >>> create_vesting_balance account07 50 TEST normal true
create_vesting_balance account07 50 TEST normal true
{
  "ref_block_num": 3979,
  "ref_block_prefix": 1838302122,
  "expiration": "2020-03-13T17:08:51",
  "operations": [[
      32,{
...
}

unlocked >>> get_vesting_balances account07
get_vesting_balances account07
[{
    "id": "1.13.79",
    "owner": "1.2.58",
...
  },{
    "id": "1.13.80",
    "owner": "1.2.58",
...
  }
]
# ================================================================================

# ================================================================================
# Create Bitcoin address for SON account in shared SON wallet
bitcoin-core.cli -rpcconnect=99.79.189.95 -rpcport=22222 -rpcuser=1 -rpcpassword=1 -rpcwallet="son-wallet" getnewaddress
2NCGVYMNjSSwYrxGAFv53WQP6i7xu8XHEVn

bitcoin-core.cli -rpcconnect=99.79.189.95 -rpcport=22222 -rpcuser=1 -rpcpassword=1 -rpcwallet="son-wallet" walletpassphrase 9da115c9fa6fe7fd09390841ac91aee4 60

bitcoin-core.cli -rpcconnect=99.79.189.95 -rpcport=22222 -rpcuser=1 -rpcpassword=1 -rpcwallet="son-wallet" dumpprivkey 2NCGVYMNjSSwYrxGAFv53WQP6i7xu8XHEVn
cSmQ517iJaAT94SMAsLhtyicZcFggY54gg5aLCUDuwUA3ECftP24

bitcoin-core.cli -rpcconnect=99.79.189.95 -rpcport=22222 -rpcuser=1 -rpcpassword=1 -rpcwallet="son-wallet" getaddressinfo 2NCGVYMNjSSwYrxGAFv53WQP6i7xu8XHEVn
{
  "address": "2NCGVYMNjSSwYrxGAFv53WQP6i7xu8XHEVn",
  "scriptPubKey": "a914d0a7c9ec2c89c67df9c1d8dce8d786ec9a0afcac87",
  "ismine": true,
  "solvable": true,
  "desc": "sh(wpkh([c9cc7580/0'/0'/3']03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2))#4g9d62sg",
  "iswatchonly": false,
  "isscript": true,
  "iswitness": false,
  "script": "witness_v0_keyhash",
  "hex": "0014d244cd683056c918a4d8f5cb1adce7a86558e253",
  "pubkey": "03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2",
...
}
# ================================================================================

# ================================================================================
# Create SON account, and get its ID
unlocked >>> create_son account07 "http://www.account07.com" 1.13.79 1.13.80 [[bitcoin, 03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2]] true
create_son account07 "http://www.account07.com" 1.13.79 1.13.80 [[bitcoin, 03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2]] true
{
  "ref_block_num": 4171,
  "ref_block_prefix": 2156837961,
  "expiration": "2020-03-13T17:20:06",
  "operations": [[
      82,{
        "fee": {
          "amount": 0,
          "asset_id": "1.3.0"
        },
        "owner_account": "1.2.58",
        "url": "http://www.account07.com",
        "deposit": "1.13.79",
        "signing_key": "TEST71FaAsTFbKyoGM7USqzS9uG78jjRv7wJnTytxyXr7CTnrHeAHJ",
        "sidechain_public_keys": [[
            "bitcoin",
            "03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2"
          ]
        ],
        "pay_vb": "1.13.80"
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "1f03b014fadc66110bef63125967a93da577cdd598ca8a1ffebf36b7e21fdfc3b85587e7f3e5604b336c6fc0dd3ab3d109022c1996b77a13a374349ecc9e1e1fdd"
  ]
}

unlocked >>> get_son account07
get_son account07
{
  "id": "1.27.16",
  "son_account": "1.2.58",
  "vote_id": "3:54",
  "total_votes": 0,
  "url": "http://www.account07.com",
  "deposit": "1.13.79",
  "signing_key": "TEST71FaAsTFbKyoGM7USqzS9uG78jjRv7wJnTytxyXr7CTnrHeAHJ",
  "pay_vb": "1.13.80",
  "statistics": "2.24.16",
  "status": "inactive",
  "sidechain_public_keys": [[
      "bitcoin",
      "03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2"
    ]
  ]
}
# ================================================================================

# ================================================================================
# Set the signing key for a son account (usually, its a signing key of owner account)
# Set the bitcoin address as a sidechain address for a SON account

unlocked >>> get_private_key TEST7SUmjftH3jL5L1YCTdMo1hk5qpZrhbo4MW6N2wWyQpjXkT7ByB
get_private_key TEST7SUmjftH3jL5L1YCTdMo1hk5qpZrhbo4MW6N2wWyQpjXkT7ByB
"5JKvPJkerMNVEubsbKN8Xd8wGaU1ifhv7xAwy9gFJP6yMEoTkSd"

unlocked >>> update_son account07 "" "TEST7SUmjftH3jL5L1YCTdMo1hk5qpZrhbo4MW6N2wWyQpjXkT7ByB" [[bitcoin, 03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2]] true
update_son account07 "" "TEST7SUmjftH3jL5L1YCTdMo1hk5qpZrhbo4MW6N2wWyQpjXkT7ByB" [[bitcoin, 03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2]] true
{
  "ref_block_num": 4210,
  "ref_block_prefix": 4294628244,
  "expiration": "2020-03-13T17:22:21",
  "operations": [[
      83,{
        "fee": {
          "amount": 0,
          "asset_id": "1.3.0"
        },
        "son_id": "1.27.16",
        "owner_account": "1.2.58",
        "new_signing_key": "TEST7SUmjftH3jL5L1YCTdMo1hk5qpZrhbo4MW6N2wWyQpjXkT7ByB",
        "new_sidechain_public_keys": [[
            "bitcoin",
            "03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2"
          ]
        ]
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "1f43fccecb7994fbb6138fd85ccb1b462d4ffeaa696cbe0738e0a3eaf99d1eb65c4c8e995db5c39a293d8f3056757ab199eb8b99a2972b0a9b56057e875ea4c790"
  ]
}
# ================================================================================

# ================================================================================
# Update your config file with values obtained in previous steps, and restart the witness with peerplays_sidechain plugin enabled
# ================================================================================

# Open your config file, and find options plugins

# Space-separated list of plugins to activate
plugins = witness account_history market_history accounts_list affiliate_stats bookie

# Update the line, and add peerplays_sidechain to the list of enabled plugins

# Space-separated list of plugins to activate
plugins = witness account_history market_history accounts_list affiliate_stats bookie peerplays_sidechain


# Set son-id parameter to the ID of your SON
son-id = "1.27.16"

# Set son-ids parameter to empty array
son-ids = []

# Set peerplays-private-key to the key pair belonging to the SON owner account
peerplays-private-key = ["TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]

# Leave default value
bitcoin-node-ip = 99.79.189.95

# Leave default value
bitcoin-node-zmq-port = 11111

# Leave default value
bitcoin-node-rpc-port = 22222

# Leave default value
bitcoin-node-rpc-user = 1

# Leave default value
bitcoin-node-rpc-password = 1

# Leave default value
bitcoin-wallet = son-wallet

# Leave default value
bitcoin-wallet-password = 9da115c9fa6fe7fd09390841ac91aee4

# Set bitcoin-private-key to the keypair of the bitcoin address you created for a SON in shared wallet
bitcoin-private-key = ["03eac07563aa5280a6c1db50724ffc51edca1458d3ed9a61c7455fb16f35ddccd2","cSmQ517iJaAT94SMAsLhtyicZcFggY54gg5aLCUDuwUA3ECftP24"]

# Restat the node with new configuration

Starting the node

witness_node 
# If you need the logs, the following can be helpful
# witness_node 2>&1 peerplays.log

Using the CLI wallet

In the terminal execute the CLI wallet:

# In the local terminal
./cli_wallet

If an exception is thrown and contains Remote server gave us an unexpected chain_id, then copy the remote_chain_id that is provided by it.

Pass the chain ID to the CLI wallet:

# In the local terminal
./cli_wallet --chain-id=<CHAIN-ID>

There is optionally a flag that can be passed in to connect to a remote rpc endpoint.

./cli_wallet --server-rpc-endpoint ws://96.46.49.3:8090 -u '' -p ''

Enter a password for the CLI wallet:

# In the CLI wallet
set_password <YOUR-WALLET-PASSWORD>

Unlock the CLI wallet by providing the password set earlier:

# In the CLI wallet
unlock <YOUR-WALLET-PASSWORD>

The CLI wallet will show unlocked >>> when successfully unlocked

The CLI wallet is now ready to be used.

Creating a Peerplays account

Use the CLI wallet to suggest a brain key:

# In the CLI wallet
suggest_brain_key

Make sure to backup the information that is output

Create an account using the brain key generated:

# In the CLI wallet
create_account_with_brain_key <BRAIN-KEY> <YOUR-ACCOUNT-NAME> nathan nathan true

Asset Calls

Asset Calls

list_assets

Lists all assets registered on the blockchain.

To list all assets, pass the empty string "" for the lowerbound to start at the beginning of the list, and iterate as necessary.

vector<extended_asset_object> graphene::wallet::wallet_api::list_assets(
    const string &lowerbound, 
    uint32_t limit)const
  • lowerbound: the symbol of the first asset to include in the list.

  • limit: the maximum number of assets to return (max: 100)

The list of asset objects, ordered by symbol.

create_asset

Creates a new user-issued or market-issued asset.

Many options can be changed later using update_asset().

Note: Right now this function is difficult to use because you must provide raw JSON data structures for the options objects, and those include prices and asset ids.

signed_transaction graphene::wallet::wallet_api::create_asset(
    string issuer, 
    string symbol, 
    uint8_t precision, 
    asset_options common, 
    fc::optional<bitasset_options> bitasset_opts, 
    bool broadcast = false)
  • issuer: the name or id of the account who will pay the fee and become the issuer of the new asset. This can be updated later

  • symbol: the ticker symbol of the new asset

  • precision: the number of digits of precision to the right of the decimal point, must be less than or equal to 12

  • common: asset options required for all new assets. Note that core_exchange_rate technically needs to store the asset ID of this new asset. Since this ID is not known at the time this operation is created, create this price as though the new asset has instance ID 1, and the chain will overwrite it with the new asset’s ID.

  • bitasset_opts: options specific to BitAssets. This may be null unless the market_issued flag is set in common.flags

  • broadcast: true to broadcast the transaction on the network

The signed transaction creating a new asset.

update_asset

Update the core options on an asset. There are a number of options which all assets in the network use. These options are enumerated in the asset_object::asset_options struct.

This command is used to update these options for an existing asset.

signed_transaction graphene::wallet::wallet_api::update_asset(
    string symbol, 
    optional<string> new_issuer, 
    asset_options new_options, 
    bool broadcast = false)
  • symbol: the name or id of the asset to update

  • new_issuer: if changing the asset’s issuer, the name or id of the new issuer. null if you wish to remain the issuer of the asset

  • new_options: the new asset_options object, which will entirely replace the existing options.

  • broadcast: true to broadcast the transaction on the network

The signed transaction updating the asset

update_bitasset

Update the options specific to a BitAsset.

BitAssets have some options which are not relevant to other asset types. This operation is used to update those options as an existing BitAsset.

See update_asset()

signed_transaction graphene::wallet::wallet_api::update_bitasset(
    string symbol, 
    bitasset_options new_options, 
    bool broadcast = false)
  • symbol: the name or id of the asset to update, which must be a market-issued asset

  • new_options: the new bitasset_options object, which will entirely replace the existing options.

  • broadcast: true to broadcast the transaction on the network

The signed transaction updating the Bitasset

update_asset_feed_producers

Update the set of feed-producing accounts for a BitAsset.

BitAssets have price feeds selected by taking the median values of recommendations from a set of feed producers. This command is used to specify which accounts may produce feeds for a given BitAsset.

signed_transaction graphene::wallet::wallet_api::update_asset_feed_producers(
    string symbol, 
    flat_set<string> new_feed_producers, 
    bool broadcast = false)
  • symbol: the name or id of the asset to update

  • new_feed_producers: a list of account names or ids which are authorized to produce feeds for the asset. this list will completely replace the existing list

  • broadcast: true to broadcast the transaction on the network

The signed transaction updating the BitAsset’s feed producers

publish_asset_feed

Publishes a price feed for the named asset.

Price feed providers use this command to publish their price feeds for market-issued assets. A price feed is used to tune the market for a particular market-issued asset. For each value in the feed, the median across all committee_member feeds for that asset is calculated and the market for the asset is configured with the median of that value.

The feed object in this command contains three prices:

  • A call price limit

  • A short price limit,

  • A settlement price

The call limit price is structured as (collateral asset) / (debt asset) and the short limit price is structured as (asset for sale) / (collateral asset).

Note: The asset IDs are opposite to each other, so if we’re publishing a feed for BTC, the call limit price will be PPY/BTC and the short limit price will be BTC/PPY.

The settlement price may be flipped either direction, as long as it is a ratio between the market-issued asset and its collateral.

signed_transaction graphene::wallet::wallet_api::publish_asset_feed(
    string publishing_account, 
    string symbol, 
    price_feed feed, 
    bool broadcast = false)
  • publishing_account: the account publishing the price feed

  • symbol: the name or id of the asset whose feed we’re publishing

  • feed: the price_feed object containing the three prices making up the feed

  • broadcast: true to broadcast the transaction on the network

The signed transaction updating the price feed for the given asset.

issue_asset

Issue new shares of an asset.

signed_transaction graphene::wallet::wallet_api::issue_asset(
    string to_account, 
    string amount, 
    string symbol, 
    string memo, 
    bool broadcast = false)
  • to_account: the name or id of the account to receive the new shares

  • amount: the amount to issue, in nominal units

  • symbol: the ticker symbol of the asset to issue

  • memo: a memo to include in the transaction, readable by the recipient

  • broadcast: true to broadcast the transaction on the network

The signed transaction issuing the new shares

get_asset

Returns information about the given asset.

extended_asset_object graphene::wallet::wallet_api::get_asset(
    string asset_name_or_id)const
  • asset_name_or_id: the symbol or id of the asset in question

The information about the asset stored in the block chain.

get_bitasset_data

Returns the BitAsset-specific data for a given asset. Market-issued asset’s behavior are determined both by their “BitAsset Data” and their basic asset data, as returned by get_asset().

asset_bitasset_data_object graphene::wallet::wallet_api::get_bitasset_data(
    string asset_name_or_id)const
  • asset_name_or_id: the symbol or id of the BitAsset in question

The BitAsset-specific data for this asset

fund_asset_fee_pool

Pay into the fee pool for the given asset.

User-issued assets can optionally have a pool of the core asset which is automatically used to pay transaction fees for any transaction using that asset (using the asset’s core exchange rate).

This command allows anyone to deposit the core asset into this fee pool.

signed_transaction graphene::wallet::wallet_api::fund_asset_fee_pool(
    string from, 
    string symbol, 
    string amount, 
    bool broadcast = false)
  • from: the name or id of the account sending the core asset

  • symbol: the name or id of the asset whose fee pool you wish to fund

  • amount: the amount of the core asset to deposit

  • broadcast: true to broadcast the transaction on the network

The signed transaction funding the fee pool.

reserve_asset

Burns an amount of given asset.

This command burns an amount of given asset to reduce the amount in circulation.

Note: You can't burn market-issued assets.

signed_transaction graphene::wallet::wallet_api::reserve_asset(
    string from, 
    string amount, 
    string symbol, 
    bool broadcast = false)
  • from: the account containing the asset you wish to burn

  • amount: the amount to burn, in nominal units

  • symbol: the name or id of the asset to burn

  • broadcast: true to broadcast the transaction on the network

The signed transaction burning the asset

global_settle_asset

Forces a global settling of the given asset (black swan or prediction markets).

In order to use this operation, asset_to_settle must have the global_settle flag set

When this operation is executed all open margin positions are called at the settle price. A pool will be formed containing the collateral got from the margin positions. Users owning an amount of the asset may use settle_asset() to claim collateral instantly at the settle price from the pool.

If this asset is used as backing for other BitAssets, those BitAssets will not be affected.

Note: This operation is used only by the asset issuer.

signed_transaction graphene::wallet::wallet_api::global_settle_asset(
    string symbol, 
    price settle_price, 
    bool broadcast = false)
  • symbol: the name or id of the asset to globally settle

  • settle_price: the price at which to settle

  • broadcast: true to broadcast the transaction on the network

The signed transaction settling the named asset

son-consensus-communication-and-transaction-signing-on-chain-lld

1.Purpose

The purpose of this document is to provide low-level design for the communication mechanism between SONs and transaction signing.

2. Scope

The design requirement listed in this document will be limited to the communication, consensus and transaction signing of SONs on-chain.

The document also proposes a design to create a way to know the health of an active SON.

The document takes only the Bitcoin sidechain into consideration as of this writing but can be extended to others in the future.

The document doesn’t deal with sidechain deposit handling or withdrawal.

The assumption is that we use a single PW design without creating deposit addresses.

Note1: For the simplicity of the examples, let's assume we have 3 SONs.

Note2: Code snippets provided in the document are pseudo-codes, they just illustrate basic logic and may not be syntactically correct.

2.1 Glossary

Consensus-SON: Top 2/3rd active SONs who signs transactions on behalf of the 15 active SONs takes part in the consensus and the operations. They are termed as Consensus-SONs

SON-Quorum: The availability of SONs with 2/3rd accumulated stakes via votes is a SON-Quorum.

3. Background

The Bitcoin Sidechain functionality has been implemented in the Peerplays blockchain but it doesn't take into account, the change of witnesses.

As per the current implementation of Sidechain, a multi-sig bitcoin address will be created on the bitcoin blockchain to hold the bitcoins that have been deposited into the pBTC accounts of the Peerplays users.

Every Peerplays witnesses will have a bitcoin transaction signing key for this multi-sig bitcoin address and will be required to sign any withdrawal transaction.

When a witness changes, the transaction signing key of the outgoing witness needs to be removed from the multi-sig bitcoin address and the key of the incoming witness needs to be added.

The suggested proposal is to make the Sidechain code available as a plugin and assign the responsibility for running the sidechain code to separate nodes called the Sidechain Operating Nodes (SONs).

The SON functionality will be independent of the witness functionality and SONs don't need to be changed much often.

4. Basic Idea

One of the biggest challenges of the SON project is to achieve consensus among the SONs on the blockchain.

The consensus is required among SONs to perform the following tasks,

  1. Transferring BTC to User address after withdrawal.

  2. Transferring BTC from old PW to new PW.

  3. To issue pBTC.

  4. To report on another active SON for being inactive.

Also, the challenge is that SONs have to make sure they do all the work with respect to the sidechain and relieve the witnesses of the extra load of listening to the sidechain and handling deposits and withdrawals.

But the records/statistics of the sidechain transactions, issuance of pBTC, SON health status, etc have to be kept on-chain.

The Statics of the sidechain transactions, issuance of pBTC, SON health, availability of SONs etc have to be kept on the Peerplays blockchain.

This provides a robust mechanism for anyone to get the historical performance of the SONs, near real time view of the chain fund movements.

The basic idea of how to achieve consensus is as follows,

  1. Create a peerplays account for a sidechain SON-195 - Getting issue details... STATUS , let's name it ‘son-btc-account’.

  2. Owners for the account are SONs.

  3. Weights of their signatures are proportional to the votes they receive.

  4. The weight threshold of the account is 2/3 of the total weight.

  5. Any operation related to the SON tasks has the paying account as the son account that's created.

  6. All such operations are encapsulated in proposals.

  7. So for any SON proposal to be successfully executed it needs to have 2/3 of the total authority of SONs.

Eg. SON1 weight = 7 SON2 weight = 5 SON3 weight = 3 Total weight = 15 Weight Threshold = 2/3 * 15 = 10

So signatures of one of the SON combinations (1,2), (1,3), (1,2,3) are required to execute a successful transaction/proposal.

Psuedo-code is as follows,

const auto& son_btc_account = create<account_object>( [&]( account_object& obj ) {

obj.name = "son-btc-account";

obj.statistics = create<account_statistics_object>([&]( account_statistics_object& acc_stat ){ acc_stat.owner = obj.id; }).id;

obj.owner.weight_threshold = 10;

obj.active.weight_threshold = 10;

obj.membership_expiration_date = time_point_sec::maximum();

obj.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE;

obj.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE;

// Add Authority Weights

obj.owner.add_authority( son1, 7 );

obj.active.add_authority( son1, 7 );

obj.owner.add_authority( son2, 5 );

obj.active.add_authority( son2, 5 );

obj.owner.add_authority( son3, 3 );

obj.active.add_authority( son3, 3 );

});

5. How to get SON Public Keys for Multi-Sig PW creation

We need SON public keys to create a multi-sig Bitcoin address for PW.

We get this from son_object::signing_key stored in the database.

The key is assigned during the registration of SON through CLI (refer to create_son).

We can also extend the create_son API to include a sidechain public key that is different from peerplays public key. SON-190 - Getting issue details... STATUS

6. Creation and Signing of BTC Transaction

As discussed above, we need to egress BTC transactions in case of transferring BTC to a user after withdrawal and transferring BTC from old PW to new PW.

Following steps will accomplish this,

  1. A Proposal is created with the fee-paying account as the individual SON account who is proposing.

  2. Create the BTC raw transaction.

  3. Create a BTC Transaction Send Operation with fee payer as the peerplays bitcoin sidechain account son-btc-account(weight threshold as 2/3 of SONs total weight).

  4. Encapsulate the send operation in the proposal created.

  5. Ensure the proposal lifetime is sufficient ( N*(number of SONs)*(block_creation_interval) where N is configurable i.e. 1,2,3,4 etc).

  6. Publish the proposal on to the peerplays blockchain.

  7. Each SON after receiving the proposal validated the data against the sidechain BTC database stored in the plugin locally.

  8. If appropriate, each SON signs the BTC transaction.

  9. Create a BTC Transaction Sign Operation with fee payer as the individual SON account who is signing (i.e. SON1 account, SON2 account, etc).

  10. Sign the BTC transaction and store the signature in the sign operation.

  11. Encapsulate the operation in a peerplays transaction, sign it and send it to peerplays blockchain.

  12. The sign operation is evaluated by checking the SON signature on BTC Transaction with the SON public key registered on peerplays blockchain.

  13. If evaluation succeeds, during the do_apply of sign operation the verified signatures are stored in the send operation encapsulated in the proposal created initially.

  14. After the required signatures are available or lifetime of the proposal is expired and if enough signatures to reach the weight threshold of the son-btc-account are present, the proposal is executed, signatures are sorted and BTC transaction is sent out.

As the weights in the bitcoin script and weights of the son-btc-account are the same, if proposal is executed successfully the bitcoin transaction will also be successful.

Creating send-BTC transaction proposal pseudo-code,

// Create BTC Transaction with the vins and vouts stored in SON Database

btc_tx = create_btc_transaction();

// Create BTC Transaction Send Operation

bitcoin_transaction_send_operation btc_send_op;

btc_send_op.payer = son-btc-account;

// Get the BTC vector of inputs

btc_send_op.vins = btc_tx.get_valid_vins();

// Fill the BTC vector of outputs

btc_send_op.vout = fill_vouts();

// Store BTC Transaction data i.e. hash, amount, fee etc.

btc_send_op.transaction = btc_tx;

// Create the proposal and encapsulate the send operation in it.

proposal_create_operation proposal_op;

proposal_op.fee_paying_account = son_account;

proposal_op.proposed_ops.push_back( op_wrapper( btc_send_op ) );

uint32_t lifetime = ( get_global_properties().parameters.block_interval * get_global_properties().active_sons.size() ) * 4;

proposal_op.expiration_time = time_point_sec( head_block_time().sec_since_epoch() + lifetime );

Each SON signing the send-BTC transaction proposal pseudo-code,

bitcoin_transaction_sign_operation sign_operation;

sign_operation.payer = current_son.son_account;

// Proposal ID of the send-BTC Transaction Operation

sign_operation.proposal_id = proposal_id;

// Assign SON ID

sign_operation.son_id = my_son_id;

// Get the vins from the proposal

auto vins = btc_send_op.vins;

// Sign the transaction

sign_operation.signatures = sign_transaction(btc_send_op.transaction, vins);

BTC Sign Operation Evaluator pseudo-code,

void_result bitcoin_transaction_sign_evaluator::do_evaluate( const bitcoin_transaction_sign_operation& op ) {

const auto& proposal_itr = proposal_idx.find(op.proposal_id);

FC_ASSERT(proposal_idx.end() != proposal_itr, "proposal not found");

FC_ASSERT(is_signed_by_active_son(op.son_id), "Not signed by active SON.");

const auto& son_object = get_son_object(op.son_id);

bytes public_key( public_key_data_to_bytes( son_object.signing_key.key_data ) );

auto btc_send_op = proposal_itr->proposed_transaction.operations[0].get<bitcoin_transaction_send_operation>();

// Get the vector of input txs from send-operation from proposal and verify sigs with SON Public key

auto vins = btc_send_op.vins;

FC_ASSERT( check_sigs( public_key, op.signatures, vins, btc_send_op.transaction ) );

}

void_result bitcoin_transaction_sign_evaluator::do_apply( const bitcoin_transaction_sign_operation& op ) {

database& d = db();

// Get the send-BTC Transaction Operation Proposal created

const auto& proposal = op.proposal_id( d );

// Modify the operation by adding the validated signature

d.modify( proposal, [&]( proposal_object& po ) {

auto bitcoin_transaction_send_op = po.proposed_transaction.operations[0].get<bitcoin_transaction_send_operation>();

for( size_t i = 0; i < op.signatures.size(); i++ ) {

bitcoin_transaction_send_op.transaction.vin[i].scriptWitness.push_back( op.signatures[i] );

}

po.proposed_transaction.operations[0] = bitcoin_transaction_send_op;

});

// Create proposal_update_operation and add the SON's approval to the proposal.

proposal_update_operation update_op;

update_op.fee_paying_account = op.payer;

update_op.proposal = op.proposal_id;

update_op.active_approvals_to_add = { op.payer };

d.apply_operation(*trx_state, update_op);

return void_result();

}

BTC Send Transaction Operation Evaluator Pseudo-code,

void_result bitcoin_transaction_send_evaluator::do_evaluate( const bitcoin_transaction_send_operation& op ) {

// Check if the payer of the operation is the multi signatory SON BTC peerplays account.

FC_ASSERT( son-btc-account == op.payer );

return void_result();

}

object_id_type bitcoin_transaction_send_evaluator::do_apply( const bitcoin_transaction_send_operation& op ) {

bitcoin_transaction_send_operation& mutable_op = const_cast<bitcoin_transaction_send_operation&>( op );

database& d = db();

// Make the transaction ready by sorting sigs etc

finalize_btc_tx(mutable_op);

auto new_vins = create_transaction_vins( mutable_op );

// Create the bitcoin_transaction_object to be stored on the chain.

const bitcoin_transaction_object& btc_tx = d.create< bitcoin_transaction_object >( [&]( bitcoin_transaction_object& obj )

{

obj.pw_vin = mutable_op.pw_vin.identifier;

obj.vins = new_vins;

obj.vouts = mutable_op.vouts;

obj.transaction = mutable_op.transaction;

obj.transaction_id = mutable_op.transaction.get_txid();

obj.fee_for_size = mutable_op.fee_for_size;

});

// Send out the transaction.

send_bitcoin_transaction( btc_tx );

return btc_tx.id;

}

7. SON Heart Beats

Heartbeat transactions are sent by active SONs to notify the blockchain that they are active.

The frequency of the heartbeat can be configured through chain parameter extensions.

We need these in order to mark active SONs as in_maintenance if heartbeats are missed.

Evaluation and application of the heartbeat operation pseudo-code,

void_result son_evaluator::do_evaluate(const son_heartbeat_operation& op) {

// Get SON Object from son id through son_index

son_object son = get_son_by_id(op.son_id);

// Payer for hearbeat operations are individual SON accounts

FC_ASSERT(op.payer == son.son_account);

return void_result();

}

void_result son_evaluator::do_apply(const son_heartbeat_operation& op) {

// Get SON Object from son id through son_index

son_object son = get_son_by_id(op.son_id);

// Get SON Statistics Object from son_stats_index

son_statistics_object son_stats = get_son_stats(son.statistics);

// Update the last active timestamp

db.modify( son_stats, [&]( son_statistics_object& _s)

{

_s.last_active_ts = op.ts;

});

}

8. Reporting SON Down

If any SON misses N number of heartbeats then one of the other active SONs can notify the peerplays blockchain about it.

N can be configurable with chain parameter extensions.

One of the rest of the active SON can raise a son_deactivate_operation to report on the SON which is down.

The fee-paying account for this operation should be the peerplays bitcoin sidechain account son-btc-account.

A proposal is created and the deactivate operation is encapsulated inside the proposal. (Fee-paying account for the proposal is individual SON account)

The lifetime of the proposal can be N*(number of SONs)*(block_creation_interval) where N is configurable i.e. 1,2,3,4 etc.

The rest of the SONs on receiving the proposal can validate and add their approvals to the proposal.

After the required signatures are available or once the proposal is expired, if it succeeds it is executed and the down SON status is set to in_maintenance on the blockchain.

If the down SON becomes active and sends a heartbeat while the deactivate proposal is active, we can leave the SON status as active but add up the downtime in statistics object.

Evaluation and application of the son deactivate operation pseudo-code,

void_result son_evaluator::do_evaluate(const son_deactivate_operation& op) {

// Get SON Object from son id through son_index

son_object son = get_son_by_id(op.son_id);

// Payer for hearbeat operations are individual SON accounts

FC_ASSERT(op.payer == son.son_account);

return void_result();

}

void_result son_evaluator::do_apply(const son_deactivate_operation& op) {

// Get SON Object from son id through son_index

son_object son = get_son_by_id(op.son_id);

// Get SON Statistics Object from son_stats_index

son_statistics_object son_stats = get_son_stats(son.statistics);

// Update the last active timestamp

db.modify( son, [&]( son_object& _son_obj)

{

_son_obj.status = son_status::in_maintenance;

});

db.modify( son_stats, [&]( son_statistics_object& _s)

{

_s.last_down_ts = op.ts;

});

}

Adding approvals by rest of the active SONs pseudo-code,

// Create proposal_update_operation and add the SON's approval to the proposal.

proposal_update_operation update_op;

update_op.fee_paying_account = op.payer;

update_op.proposal = op.proposal_id;

update_op.active_approvals_to_add = { op.payer };

d.apply_operation(*trx_state, update_op);

9. SON Issue pBTC

Once a required number of confirmations are reached for a transaction sending BTC from user bitcoin address to PW address, SON pBTC issue operation has to be raised to user’s peerplays account.

As discussed above similar proposal process is followed.

  1. A proposal is created by one active SON and the fee-paying account is set to the individual account of the SON. (lifetime same as discussed above)

  2. A bitcoin_issue_operation is created for which the fee-paying account is set to son-btc-account.

  3. The issue operation is encapsulated in the proposal and sent to the peerplays blockchain.

  4. Rest of the active SONs validate their plugin BTC databases and add approvals upon receiving the proposal.

  5. Once the required number of approvals (2/3 of SONs total weight) are added, proposal is executed and the pBTC is issued.

SON Issue pBTC pseudo-code,

void_result son_evaluator::do_evaluate(const bitcoin_issue_operation& op) {

// Check if the payer of the operation is the multi signatory SON BTC peerplays account.

FC_ASSERT( son-btc-account == op.payer );

// Check if the vin tx input address is user registered address on peerplays blockchain.

FC_ASSERT( is_address_registered(op.vin_addres))

return void_result();

}

void_result son_evaluator::do_apply(const bitcoin_issue_operation& op) {

// Get the peerplays account to issue pBTC

const auto& account_to_issue = get_account_to_issue(op.vin_address);

// Get the amount to issue i.e. equal to BTC amount transferred

const auto& amount_to_issue = get_amount_to_issue(op.amount);

// Follow the normal UIA issue procedure.

add_issue(account_to_issue, amount_to_issue);

}

Adding approvals by rest of the active SONs pseudo-code,

// Create proposal_update_operation and add the SON's approval to the proposal.

proposal_update_operation update_op;

update_op.fee_paying_account = op.payer;

update_op.proposal = op.proposal_id;

update_op.active_approvals_to_add = { op.payer };

d.apply_operation(*trx_state, update_op);

10. Choosing the SON who creates the next proposal

In all the above operations, any one of the SON has to raise the initial proposal.

If multiple proposals are raised for the same BTC transaction, only one of them is valid and the rest of them should be rejected.

To achieve this we can use one of the existing witnesses shuffled or scheduled algorithms.

With these algorithms in place, all the SONs know when is their slot to publish a proposal for the next event.

The detailed design for this is out of the scope of this document and should be part of SON plugin handling.

For the existing witness scheduling algorithm please refer to this link.

11. Data Structures

11.1 bitcoin_transaction_send_operation

We can retain most of the implementation from the sidechain branch.

It can be found here.

11.2 bitcoin_transaction_sign_operation

We can retain most of the implementation from the sidechain branch.

It can be found here.

11.3 son_heartbeat_operation

11.4 son_deactivate_operation

12. SON changes during Maintenance

One of the many things we have to do during maintenance is updating the PW and the multi signatory SON account (son-btc-account).

As discussed above the weights of signatures is the same for both PW and the multi signatory SON account, we have to change both accordingly after the SON weight changes or SON changes.

The change of PW is discussed here.

Eg. Weights of the SONs have changed from the previous example above and a new SON is active. SON1 weight = 10 SON2 weight = 5 SON4 weight = 6 Total weight = 21 Weight Threshold = 2/3 * 21 = 14

So signatures of one of the SON combinations (1,2), (1,4), (1,2,4) are required to execute a successful transaction/proposal.

For changing the weights of peerplays SON account following is the pseudo-code,

modify( sidechain_account, [&]( account_object& obj ) {

// Add new weight threshold

obj.owner.weight_threshold = 14;

obj.active.weight_threshold = 14;

// Add new authority for SON1

obj.owner.add_authority( son1, 10 );

obj.active.add_authority( son1, 10 );

// Add new authority for SON2

obj.owner.add_authority( son2, 5 );

obj.active.add_authority( son2, 5 );

// Remove the SON3 Authority

obj.owner.add_authority( son3, 0 );

obj.active.add_authority( son3, 0 );

// Add new authority for SON4

obj.owner.add_authority( son4, 6 );

obj.active.add_authority( son4, 6 );

});

13. Conclusion

This approach can greatly relieve the peerplays blockchain of any type of sidechain listening, deposit, and withdrawal operations.

Only the transactions which are needed to be logged are processed by the nodes other than SONs.

All the operations which need multiple signatures can directly be accepted by everyone on the blockchain as the proposals ensure all signatures present before execution.

The most important aspect of this design is we can re-use most of the existing bitcoin-related sidechain code which can reduce our development effort.

Database API

The database API is available from the full node via web-sockets.

Objects

get_objects

Get the objects corresponding to the provided IDs.

If any of the provided IDs does not map to an object, a null variant is returned in its position.

fc::variants graphene::app::database_api::get_objects(
    const vector<object_id_type> &ids, 
    optional<bool> subscribe = optional<bool>())const
  • ids: IDs of the objects to retrieve

  • subscribe: true to subscribe to the queried objects; false to not subscribe; null to subscribe or not subscribe according to current auto-subscription setting (see set_auto_subscription)

The objects retrieved, in the order they are mentioned in ids.

Subscriptions

set_subscribe_callback

Register a callback handle which then can be used to subscribe to object database changes.

Note: auto-subscription is enabled by default and can be disabled with set_auto_subscription

void graphene::app::database_api::set_subscribe_callback(
    std::function<void(const variant&)> cb, 
    bool notify_remove_create, )
  • cb: The callback handle to register

  • notify_remove_create: Whether subscribe to universal object creation and removal events. If this is set to true, the API server will notify all newly created objects and ID of all newly removed objects to the client, no matter whether client subscribed to the objects. By default, API servers don’t allow subscribing to universal events, which can be changed on server startup.

set_pending_transaction_callback

Register a callback handle which will get notified when a transaction is pushed to database.

Note: A transaction can be pushed to the database and be popped from the database several times while processing, before and after,, included in a block. Every time a push is done, the client will be notified.

void graphene::app::database_api::set_pending_transaction_callback(
    std::function<void(const variant &signed_transaction_object)> cb)
  • cb: The callback handle to register

set_block_applied_callback

Register a callback handle which will get notified when a block is pushed to database.

void graphene::app::database_api::set_block_applied_callback(
    std::function<void(const variant &block_id)> cb)
  • cb: The callback handle to register

cancel_all_subscriptions

Stop receiving any notifications.

This unsubscribes from all subscribed markets and objects.

void graphene::app::database_api::cancel_all_subscriptions()

Blocks and transactions

get_block_header

Retrieve a block header.

optional<block_header> graphene::app::database_api::get_block_header(
    uint32_t block_num)const
  • block_num: Height of the block whose header should be returned

  • The header of the referenced block, or null if no matching block was foun

get_block

Retrieve a full, signed block.

optional<signed_block> graphene::app::database_api::get_block(
    uint32_t block_num)const
  • block_num: Height of the block to be returned

The referenced block, or null if no matching block was found.

get_transaction

Fetch an individual transaction.

processed_transaction graphene::app::database_api::get_transaction(
    uint32_t block_num, uint32_t trx_in_block)const
  • block_num: height of the block to fetch

  • trx_in_block: the index (sequence number) of the transaction in the block, starts from 0

The transaction at the given position.

get_recent_transaction_by_id

optional<signed_transaction> graphene::app::database_api::get_recent_transaction_by_id(
    const transaction_id_type &txid)const
  • txid: hash of the transaction

The corresponding transaction if found, or null if not found.

If the transaction has not expired, this method will return the transaction for the given ID or it will return NULL if it is not known. Just because it is not known does not mean it wasn’t included in the blockchain.

Globals

get_chain_properties

Retrieve the graphene::chain::chain_property_object associated with the chain.

chain_property_object graphene::app::database_api::get_chain_properties()const

get_global_properties

Retrieve the current graphene::chain::global_property_object.

global_property_object graphene::app::database_api::get_global_properties()const

get_config

Retrieve compile-time constants.

fc::variant_object graphene::app::database_api::get_config()const

get_chain_id

Get the chain ID.

chain_id_type graphene::app::database_api::get_chain_id()cons

get_dynamic_global_properties

Retrieve the current graphene::chain::dynamic_global_property_object.

dynamic_global_property_object graphene::app::database_api::get_dynamic_global_properties()const

Keys

get_key_references

Get all accounts that refer to the specified public keys in their owner authority, active authorities or memo key.

vector<flat_set<account_id_type>> graphene::app::database_api::get_key_references(
    vector<public_key_type> keys)const
  • keys: a list of public keys to query

ID of all accounts that refer to the specified keys.

Accounts

get_accounts

Get a list of accounts by names or IDs.

This function has semantics identical to get_objects****

vector<optional<account_object>> graphene::app::database_api::get_accounts(
    const vector<std::string> &account_names_or_ids, 
    optional<bool> subscribe = optional<bool>())const
  • account_names_or_ids: names or IDs of the accounts to retrieve

  • subscribe: true to subscribe to the queried account objects; false to not subscribe; null to subscribe or not subscribe according to current auto-subscription setting (see set_auto_subscription)

The accounts corresponding to the provided names or IDs.

get_full_accounts

Fetch all objects relevant to the specified accounts and optionally subscribe to updates.

This function fetches all relevant objects for the given accounts, and subscribes to updates to the given accounts. If any of the strings innames_or_ids cannot be tied to an account, that input will be ignored. All other accounts will be retrieved and subscribed.

std::map<string, full_account> graphene::app::database_api::get_full_accounts(
    const vector<string> &names_or_ids, 
    optional<bool> subscribe = optional<bool>())
  • names_or_ids: Each item must be the name or ID of an account to retrieve

  • subscribe: true to subscribe to the queried full account objects; false to not subscribe; null to subscribe or not subscribe according to current auto-subscription setting (see set_auto_subscription)

Map of string from names_or_ids to the corresponding account.

get_account_by_name

Get info of an account by name.

optional<account_object> graphene::app::database_api::get_account_by_name(
    string name)const
  • name: Name of the account to retrieve

The account holding the provided name.

get_account_references

Get all accounts that refer to the specified account in their owner or active authorities.

vector<account_id_type> graphene::app::database_api::get_account_references(
    const std::string account_name_or_id)const
  • account_name_or_id: Account name or ID to query

All accounts that refer to the specified account in their owner or active authorities

lookup_account_names

Get a list of accounts by name.

This function has semantics identical to get_objects, but doesn’t subscribe

vector<optional<account_object>> graphene::app::database_api::lookup_account_names(
    const vector<string> &account_names)const
  • account_names: Names of the accounts to retrieve

The accounts holding the provided names.

lookup_accounts

Get names and IDs for registered accounts.

Note: In addition to the common auto-subscription rules, this API will subscribe to the returned account only if limit is 1.

map<string, account_id_type> graphene::app::database_api::lookup_accounts(
    const string &lower_bound_name, 
    uint32_t limit, 
    optional<bool> subscribe = optional<bool>())const
  • lower_bound_name: Lower bound of the first name to return

  • limit: Maximum number of results to return must not exceed 1000

  • subscribe: true to subscribe to the queried account objects; false to not subscribe; null to subscribe or not subscribe according to current auto-subscription setting (see set_auto_subscription).

Map of account names to corresponding IDs.

get_account_count

Get the total number of accounts registered with the blockchain.

uint64_t graphene::app::database_api::get_account_count()const

Balances

get_account_balances

Get an account’s balances in various assets.

vector<asset> graphene::app::database_api::get_account_balances(
    const std::string &account_name_or_id, 
    const flat_set<asset_id_type> &assets)const
  • account_name_or_id: name or ID of the account to get balances for.

  • assets: IDs of the assets to get balances of; if empty, get all assets account has a balance in.

Balances of the account.

get_named_account_balances

Semantically equivalent to get_account_balances.

vector<asset> graphene::app::database_api::get_named_account_balances(
    const std::string &name, 
    const flat_set<asset_id_type> &assets)const
  • account_name_or_id: name or ID of the account to get balances for.

  • assets: IDs of the assets to get balances of; if empty, get all assets account has a balance in.

Balances of the account.

get_balance_objects

vector<balance_object> graphene::app::database_api::get_balance_objects(
    const vector<address> &addrs)const
  • addrs: a list of addresses

All unclaimed balance objects for the addresses.

get_vested_balances

Calculate how much assets in the given balance objects are able to be claimed at current head block time.

vector<asset> graphene::app::database_api::get_vested_balances(
    const vector<balance_id_type> &objs)const
  • objs: a list of balance object IDs

A list indicating how much asset in each balance object is available to be claimed.

get_vesting_balances

Return all vesting balance objects owned by an account.

vector<vesting_balance_object> graphene::app::database_api::get_vesting_balances(
    const std::string account_name_or_id)const
  • account_name_or_id: name or ID of an account

All vesting balance objects owned by the account.

Assets

get_assets

Get a list of assets by symbol names or IDs.

Semantically equivalent to get_objects.

vector<optional<extended_asset_object>> graphene::app::database_api::get_assets(
    const vector<std::string> &asset_symbols_or_ids, 
    optional<bool> subscribe = optional<bool>())const
  • asset_symbols_or_ids: symbol names or IDs of the assets to retrieve

  • subscribe: true to subscribe to the queried asset objects; false to not subscribe; null to subscribe or not subscribe according to current auto-subscription setting (see set_auto_subscription)

The assets corresponding to the provided symbol names or IDs.

list_assets

Get assets alphabetically by symbol name.

vector<extended_asset_object> graphene::app::database_api::list_assets(
    const string &lower_bound_symbol, 
    uint32_t limit)const
  • lower_bound_symbol: Lower bound of symbol names to retrieve

  • limit: Maximum number of assets to fetch (must not exceed 101)

The assets found.

lookup_asset_symbols

Get a list of assets by symbol names or IDs.

Semantically equivalent to get_objects, but doesn’t subscribe.

vector<optional<extended_asset_object>> graphene::app::database_api::lookup_asset_symbols(
    const vector<string> &symbols_or_ids)const
  • symbols_or_ids: symbol names or IDs of the assets to retrieve

The assets corresponding to the provided symbols or IDs

Markets / Feeds

get_order_book

Returns the order book for the market base

order_book graphene::app::database_api::get_order_book(
    const string &base, 
    const string &quote, 
    unsigned limit = 50)const
  • base: symbol name or ID of the base asset

  • quote: symbol name or ID of the quote asset

  • limit: depth of the order book to retrieve, for bids and asks each, capped at 50

Order book of the market.

get_limit_orders

Get limit orders in a given market.

vector<limit_order_object> graphene::app::database_api::get_limit_orders(
    std::string a, 
    std::string b, 
    uint32_t limit)const
  • a: symbol or ID of asset being sold

  • b: symbol or ID of asset being purchased

  • limit: Maximum number of orders to retrieve

The limit orders, ordered from least price to greatest.

get_call_orders

Get call orders (aka margin positions) for a given asset.

vector<call_order_object> graphene::app::database_api::get_call_orders(
    const std::string &a, 
    uint32_t limit)const
  • a: symbol name or ID of the debt asset

  • limit: Maximum number of orders to retrieve

The call orders, ordered from earliest to be called to latest

get_settle_orders

Get forced settlement orders in a given asset.

vector<force_settlement_object> graphene::app::database_api::get_settle_orders(
    const std::string &a, 
    uint32_t limit)const
  • a: Symbol or ID of asset being settled

  • limit: Maximum number of orders to retrieve

The settle orders, ordered from earliest settlement date to latest.

get_margin_positions

Get all open margin positions of a given account.

Similar to get_call_orders_by_account, but without pagination.

vector<call_order_object> graphene::app::database_api::get_margin_positions(
    const std::string account_name_or_id)const
  • account_name_or_id: name or ID of an account

All open margin positions of the account.

subscribe_to_market

Request notification when the active orders in the market between two assets changes.

Callback will be passed a variant containing a vector<pair<operation, operation_result>>.

The vector will contain, in order, the operations which changed the market, and their results

void graphene::app::database_api::subscribe_to_market(std::function<void(
    const variant&)> callback, 
    const std::string &a, 
    const std::string &b, )
  • callback: Callback method which is called when the market changes

  • a: symbol name or ID of the first asset

  • b: symbol name or ID of the second asset

unsubscribe_from_market

Unsubscribe from updates to a given market.

void graphene::app::database_api::unsubscribe_from_market(
    const std::string &a, 
    const std::string &b)
  • a: symbol name or ID of the first asset

  • b: symbol name or ID of the second asset

get_ticker

Returns the ticker for the market assetA:assetB.

market_ticker graphene::app::database_api::get_ticker(
    const string &base, 
    const string &quote)const
  • base: symbol name or ID of the base asset

  • quote: symbol name or ID of the quote asset

The market ticker for the past 24 hours.

get_24_volume

Returns the 24 hour volume for the market assetA:assetB.

market_volume graphene::app::database_api::get_24_volume(
    const string &base, 
    const string &quote)const
  • base: symbol name or ID of the base asset

  • quote: symbol name or ID of the quote asset

The market volume over the past 24 hours.

get_trade_history

Returns recent trades for the market base:quote, ordered by time, most recent first.

Note: Currently, timezone offsets are not supported. The time must be UTC.

The range is [stop, start). In case there are more than 100 trades occurring in the same second, this API only returns the first 100 records; use get_trade_history_by_sequence to query for the rest.

vector<market_trade> graphene::app::database_api::get_trade_history(
    const string &base, 
    const string &quote, 
    fc::time_point_sec start, 
    fc::time_point_sec stop, 
    unsigned limit = 100)const
  • base: symbol or ID of the base asset

  • quote: symbol or ID of the quote asset

  • start: Start time as a UNIX timestamp, the latest trade to retrieve

  • stop: Stop time as a UNIX timestamp, the earliest trade to retrieve

  • limit: Number of transactions to retrieve, capped at 100.

Recent transactions in the market

Witnesses

get_witnesses

Get a list of witnesses by ID.

Semantically equivalent to get_objects, but doesn’t subscribe.

vector<optional<witness_object>> graphene::app::database_api::get_witnesses(
    const vector<witness_id_type> &witness_ids)const
  • witness_ids: IDs of the witnesses to retrieve

The witnesses corresponding to the provided IDs.

get_witness_by_account

Get the witness owned by a given account.

fc::optional<witness_object> graphene::app::database_api::get_witness_by_account(
    const std::string account_name_or_id)const
  • account_name_or_id: The name or ID of the account whose witness should be retrieved

The witness object, or null if the account does not have a witness.

lookup_witness_accounts

Get names and IDs for registered witnesses.

map<string, witness_id_type> graphene::app::database_api::lookup_witness_accounts(
    const string &lower_bound_name, uint32_t limit)const
  • lower_bound_name: Lower bound of the first name to return

  • limit: Maximum number of results to return must not exceed 1000

Map of witness names to corresponding IDs.

get_witness_count

Get the total number of witnesses registered with the blockchain.

uint64_t graphene::app::database_api::get_witness_count()const

Committee members

get_committee_members

Get a list of committee_members by ID.

Semantically equivalent to get_objects, but doesn’t subscribe.

vector<optional<committee_member_object>> graphene::app::database_api::get_committee_members(
    const vector<committee_member_id_type> &committee_member_ids)const
  • committee_member_ids: IDs of the committee_members to retrieve

The committee_members corresponding to the provided IDs.

get_committee_member_by_account

Get the committee_member owned by a given account.

fc::optional<committee_member_object> graphene::app::database_api::get_committee_member_by_account(
    const string account_name_or_id)const
  • account_name_or_id: The name or ID of the account whose committee_member should be retrieved

The committee_member object, or null if the account does not have a committee_member.

lookup_committee_member_accounts

Get names and IDs for registered committee_members.

map<string, committee_member_id_type> graphene::app::database_api::lookup_committee_member_accounts(
    const string &lower_bound_name, 
    uint32_t limit)const
  • lower_bound_name: Lower bound of the first name to return

  • limit: Maximum number of results to return must not exceed 1000

Map of committee_member names to corresponding IDs

Workers

get_workers_by_account

Get the workers owned by a given account.

vector<optional<worker_object>> graphene::app::database_api::get_workers_by_account(
    const std::string account_name_or_id)const
  • account_name_or_id: The name or ID of the account whose worker should be retrieved

A list of worker objects owned by the account.

Votes

lookup_vote_ids

Given a set of votes, returns the objects they are voting for.

This will be a mixture of committee_member_objects, witness_objects, and worker_objects

vector<variant> graphene::app::database_api::lookup_vote_ids(
    const vector<vote_id_type> &votes)const
  • votes: a list of vote IDs

The referenced objects

The results will be in the same order as the votes. Null will be returned for any vote IDs that are not found.

Authority / Validation

get_transaction_hex

Get a hexdump of the serialized binary form of a transaction.

std::string graphene::app::database_api::get_transaction_hex(
    const signed_transaction &trx)const
  • trx: a transaction to get hexdump from

The hexdump of the transaction.

get_required_signatures

This API will take a partially signed transaction and a set of public keys that the owner has the ability to sign for and return the minimal subset of public keys that should add signatures to the transaction.

set<public_key_type> graphene::app::database_api::get_required_signatures(
    const signed_transaction &trx, 
    const flat_set<public_key_type> &available_keys)const
  • trx: the transaction to be signed

  • available_keys: a set of public keys

A subset of available_keys that could sign for the given transaction.

get_potential_signatures

This method will return the set of all public keys that could possibly sign for a given transaction. This call can be used by wallets to filter their set of public keys to just the relevant subset prior to calling get_required_signatures to get the minimum subset.

set<public_key_type> graphene::app::database_api::get_potential_signatures(
    const signed_transaction &trx)const
  • trx: the transaction to be signed

A set of public keys that could possibly sign for the given transaction.

get_potential_address_signatures

This method will return the set of all addresses that could possibly sign for a given transaction.

set<address> graphene::app::database_api::get_potential_address_signatures(
    const signed_transaction &trx)const
  • trx: the transaction to be signed

A set of addresses that could possibly sign for the given transaction.

verify_authority

Check whether a transaction has all of the required signatures

bool graphene::app::database_api::verify_authority(
    const signed_transaction &trx)const
  • trx: a transaction to be verified

true if the trx has all of the required signatures, otherwise throws an exception.

verify_account_authority

Verify that the public keys have enough authority to approve an operation for this account.

bool graphene::app::database_api::verify_account_authority(
    const string &account_name_or_id, 
    const flat_set<public_key_type> &signers)const
  • account_name_or_id: name or ID of an account to check

  • signers: the public keys

true if the passed in keys have enough authority to approve an operation for this account.

validate_transaction

Validates a transaction against the current state without broadcasting it on the network.

processed_transaction graphene::app::database_api::validate_transaction(
const signed_transaction &trx)const
  • trx: a transaction to be validated

A processed_transaction object if the transaction passes the validation, otherwise an exception will be thrown.

get_required_fees

For each operation calculate the required fee in the specified asset type.

vector<fc::variant> graphene::app::database_api::get_required_fees(
    const vector<operation> &ops, 
    const std::string &asset_symbol_or_id)const
  • ops: a list of operations to be query for required fees

  • asset_symbol_or_id: symbol name or ID of an asset that to be used to pay the fees

A **list of objects which indicates required fees of each operation

Proposed Transactions

get_proposed_transactions

Gets a set of proposed transactions (proposals) that the specified account can add approval to or remove approval from.

vector<proposal_object> graphene::app::database_api::get_proposed_transactions(
    const std::string account_name_or_id)const
  • account_name_or_id: The name or ID of an account

A set of proposed transactions that the specified account can act on.

Blinded balances

get_blinded_balances

Gets the set of blinded balance objects by commitment ID.

vector<blinded_balance_object> graphene::app::database_api::get_blinded_balances(
    const flat_set<commitment_type> &commitments)const
  • commitments: a set of commitments to query for

The set of blinded balance objects by commitment ID.

Introduction to Permissions

A brief explanation of role-based & resource permissions for Peerplays objects.

1. Types of Permissions in Peerplays

There are three functions available in the CLI Wallet to produce permission settings:

  1. create_custom_permission

  2. create_custom_account_authority

  3. create_account_role

The first two functions deal with creating Hierarchical Role-based Permissions (HRP). The third is used to provide resource permissions with account roles.

HRP is a feature of the Peerplays blockchain which helps to increase the security of user accounts. Users don’t have to use their active and owner keys for everything they do on the chain. Instead, they can create role based custom permissions and map them to different keys other than active and owner keys. They can then use these custom keys to sign transactions.

As opposed to HRP mentioned above, resource permissions are controlled by the owner of a resource (such as NFT metadata). These are similar to IAM permissions in an AWS Cloud environment.

2. Hierarchical Role-based Permissions (HRP)

To create a custom HRP, the first step is to create the custom permission. Then the custom permission will be mapped to the actual operations present on the blockchain by creating a related custom account authority.

Some of the following functions need Operation IDs. You can find a list of .

2.1. create_custom_permission

This function creates a new custom permission.

The basic structure of the create_custom_permission function looks like this:

Parameters

The auth parameter is a JSON object which looks like this:

This represents an authority structure, account_auths represents the amount of weight each account has on our account, in this example 1.2.52 has a weight of 1.

key_auths represents the amount of weight each public key has on this account, in this example TEST71ADtL4fzjGKErk9nQJrABmCPUR8QCjkCUNfdmgY5yDzQGhwto has a weight of 1.

weight_threshold represents the required weight for a transaction to be signed successfully.

In this example, either 1.2.52 can sign with their active key or TEST71ADtL4fzjGKErk9nQJrABmCPUR8QCjkCUNfdmgY5yDzQGhwto can be used to sign a transaction successfully because they each have a weight of 1, and only 1 is required by the threshold.

Example Call

2.2. get_custom_permissions

This function returns the custom permissions that have been created by the given account.

The basic structure of the get_custom_permission function looks like this:

Parameters

Example Call

2.3. update_custom_permission

This function updates an existing permission with the new authority object that you supply.

The basic structure of the update_custom_permission function looks like this:

Parameters

Example Call

Here we removed the key_auths and added 1.2.53 with weight 1, which is equal to weight_threshold , so 1.2.53 can alone sign the transaction successfully.

The new authority object will replace the old authority object using this function call. Make sure that the authority object that you supply here is set exactly as you'd like.

2.4. create_custom_account_authority

Creating a custom authority maps the created with the actual operations present on the blockchain. It also has expiry time by when this custom permission is no longer valid on any given account and operation combination.

The basic structure of the create_custom_account_authority function looks like this:

Parameters

A valid timestamp looks like this: "2019-11-22T18:30:00"

Example Call

Basically this represents a full HRP where the transfer operation on account01 can be done by authorities present in 1.27.0 instead of account owner account01.

2.5. update_custom_account_authority

This function can be used to update existing valid_from and valid_to times.

The basic structure of the update_custom_account_authority function looks like this:

Parameters

A valid timestamp looks like this: "2019-11-22T18:30:00"

Example Call

2.6. delete_custom_permission

This function is used to delete an existing custom permission.

This will delete all the custom account authorities linked to this permission as well.

A cascading delete!

The basic structure of the delete_custom_permission function looks like this:

Parameters

Example Call

2.7. delete_custom_account_authority

This function is used to delete an account authority attached to a permission.

The basic structure of the delete_custom_account_authority function looks like this:

Parameters

Example Call

3. Resource Permissions with Account Roles

Resource permissions can be granted by applying account roles to those resources. The allowed permissions are attached to the role. Then accounts can be added to the role to grant them the permissions the role provides.

Some of the following functions need Operation IDs. You can find a list of .

3.1. create_account_role

This function creates an account role.

The basic structure of the create_account_role function looks like this:

Parameters

A valid timestamp looks like this: "2020-09-04T13:43:39"

Example Call

This command effectively limits any NFT to be sold or transferred between only three accounts, 1.2.40, 1.2.41, and 1.2.43.

3.2. get_account_roles_by_owner

You can use this to find all the account roles by their owner.

The basic structure of the get_account_roles_by_owner function looks like this:

Parameters

Example Call

3.3. update_account_role

As a resource owner, you can update the operations and whitelisted accounts present in an account role. This helps in blacklisting any users from selling or transferring NFTs or any resources.

The basic structure of the update_account_role function looks like this:

Parameters

A valid timestamp looks like this: "2020-09-04T13:43:39"

Example Call

88 offer_operation is added.

95 nft_safe_transfer_from_operation is removed.

1.2.42 account is added to the whitelist.

1.2.40 account is removed from the whitelist.

3.4. delete_account_role

This function deletes an account role.

Once an account role is deleted, restrictions on resource access no longer work!

The basic structure of the delete_account_role function looks like this:

Parameters

Example Call

4. Related Documents

The functions listed in this guide will cost transaction fees. To calculate how much PPY you'll need to make these transactions and meet your development goals, please see the guide.

Creating User Issued Assets

A guide to create UIAs, also known as Fan Tokens or Community Asset Tokens (CATs).

1. Creating User Issued Assets (UIAs)

There are many reasons to create assets. Peerplays allows individuals and companies to create and issue their own tokens for anything they can imagine. The potential use cases for these User Issued Assets (UIAs) are innumerable. On the one hand, UIAs can be used as simple event tickets deposited on the customers mobile phone to enter a concert or movie. On the other hand, they can be used for crowd funding, ownership tracking, or even to sell equity of a company in form of stock. UIAs are incredibly versatile and can help solve a plethora of use cases like...

  • event tickets

  • reputation points

  • loyalty reward points

  • flight miles

  • company shares

  • fan credits

  • crowd funding

  • digital property

All you need to do is to define your preferred parameters for your coin, such as supply, precision, symbol, and description to see your coin’s birth after only a few seconds. From that point on, you can issue some of your coins to whomever you want, sell them, and see them instantly traded against any other existing coin on Peerplays.

Unless you want some restrictions, as the issuer, you have certain privileges over your coin. For instance, you can allow trading only in certain market pairs and define who actually is allowed to hold your coin by using whitelists and blacklists. An issuer can opt-out of their privileges indefinitely for the sake of trust and reputation.

As the owner of your new coin, you don’t need to take care of all the technical details of blockchain technology, such as distributed consensus algorithms, blockchain development, or integration. You don’t even need to run any mining equipment or servers, at all.

The regulations that apply to each kind of token vary widely and are often different in every jurisdiction. Hence, Peerplays comes with tools that allow issuers to remain compliant with all applicable regulations when issuing assets assuming regulators allow such assets in the first place.

1.1. User Issued Assets vs. Market Issued Assets

A User Issued Asset allows the issuer to control the supply of the asset. A Market Issued Asset (MIA, and also known as a Market Pegged Asset, MPA, or Smart Coin) puts the control of the asset's supply in the hands of the market.

Market issued assets are used for pegging the value of an asset to another underlying asset. This type of asset requires collateral to back its value and a fair market price feed so the market can automatically trigger margin calls to balance the market asset value. Market issued assets will be the subject of another guide.

User issued assets are controlled and distributed by the issuing user. This guide will focus on the creation of UIAs.

1.2. Creating Assets

create_asset

This function creates a new user issued or market issued asset. Many of the asset's options can be changed later using update_asset. You must provide raw JSON data structures for the options object.

The basic structure of the create_asset function looks like this:

Parameters

Example Call

In this example call we used the following settings for the common parameter:

Please see section for an explanation of the common parameter!

Important Note:

The null for the second to last parameter is essential for making a user issued asset.

A set of curly braces, {} for the parameter could be used to construct a market issued asset, but that is the subject of another guide.

1.3. Updating Assets

A UIA can be modified by the issuer after its creation. A separate call, update_asset, has been created for this purpose.

What can and cannot be changed? Except for the symbol and precision, every parameter, option, or setting can be updated.

Note that once a permission is removed, it can never be re-enabled again!

update_asset

This function updates the core options on an asset. There are a number of options which all assets in the network use. These options are enumerated in the asset_object::asset_options struct. This command is used to update these options for an existing asset.

The basic structure of the update_asset function looks like this:

Parameters

Example Call

In this example call we used the following settings for the common parameter:

Please see section for an explanation of the common parameter!

Using update_asset will overwrite all the perviously set options with the new options you enter here. So make sure all the options you need are present in the new options object!

1.4. Asset Options

The asset_options object contains the options that are common to all assets. This is why it's necessary to supply for both UIAs and MIAs. The options need to be passed as a raw JSON object that contains these settings:

Let's break these down one-by-one. Pay special attention to the permissions and flags as they are the most complicated part of the options object.

permissions & flags

Permissions and flags go together. Permissions settings determine if the issuer has the ability to update the corresponding flags. The flags are the actual on-off switches for the various asset options. Here are the available flags and their effects:

  • charge_market_fee: an issuer-specified percentage of all market trades in this asset is paid to the issuer.

  • white_list: accounts must be white-listed in order to hold this asset.

  • override_authority: issuer may transfer asset back to their own account from another account.

  • transfer_restricted: require the issuer to be one party to every transfer.

  • disable_force_settle: disable force settling.

  • global_settle: (only for MIAs) allows market asset issuer to force a global settling - this may be set in permissions, but should not be set as a flag. Unless, for instance, a prediction market has to be resolved. If this flag has been enabled, no further shares can be borrowed!

  • disable_confidential: allow the asset to be used with confidential transactions.

  • witness_fed_asset: allow the asset to be fed by witnesses.

  • committee_fed_asset: allow the asset to be fed by the committee.

The permissions/flags in the asset_details are integers and are a sum of the following mapping:

So in our case, we set flags to 0, which means all of these are disabled initially. The permissions is set to 79, which means that "charge_market_fee", "white_list", "override_authority", and "disable_confidential" are able to be modified later. The other properties are immutable since they were set to false initially.

exchange rate

The core_exchange_rate option consists of a base section and a quote section:

The idea is to create a ratio of an amount of PPY and an amount of the new asset.

In this example, we have 21 PPY and 76,399 of the new asset (BTFUN). This would make the exchange rate 3,638.05 BTFUN per 1 PPY. (76399 / 21 = 3,638.05)

The asset_id in the base section will always be "1.3.0", the ID of PPY.

The asset_id in the quote section will be unknown at the time the asset is being created. That's ok. Putting "1.3.1" here will be detected and overwritten by the blockchain with the new ID. Then you can get the new ID with the get_asset function.

1.5. Issuing Assets

So far creating assets with create_asset doesn't actually produce the new tokens into anyone's account. For that we use the issue_asset function.

issue_asset

Issues new shares of an asset that exists via create_asset.

The basic structure of the issue_asset function looks like this:

Parameters

Example Call

2. Reserved Tokens

Some token names (symbols) are reserved by the blockchain because they are assets that already exist, on or off-chain. This is to avoid confusion and prevent scams. The most popular assets have been reserved and are listed below. The symbols listed here are controlled by the Peerplays SONs son-account. If a genuine user wants to create an asset with the symbol, the SONs will raise a proposal and the Witnesses will vote to transfer the ownership to the user.

2.1. List of Reserved Tokens

3. Related Documents

The functions listed in this guide will cost transaction fees. To calculate how much PPY you'll need to make these transactions and meet your development goals, please see the guide.

return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::create_custom_permission(
    string owner, 
    string permission_name, 
    authority auth, 
    bool broadcast)
When using the cli_wallet...
create_custom_permission <owner> <permission_name> <auth> true

name

data type

description

details

owner

string

The name or id of the account who is creating the permission.

n/a

permission_name

string

The name of the permission.

n/a

auth

authority

This is a JSON object which describes an account authority. See below for details.

a JSON object

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

{
  "weight_threshold": 1,
  "account_auths": [["1.2.52",1]],
  "key_auths": [["TEST71ADtL4fzjGKErk9nQJrABmCPUR8QCjkCUNfdmgY5yDzQGhwto",1]],
  "address_auths": []
}
create_custom_permission account01 perm1 { "weight_threshold": 1,  "account_auths": [["1.2.52",1]], "key_auths": [["TEST71ADtL4fzjGKErk9nQJrABmCPUR8QCjkCUNfdmgY5yDzQGhwto",1]], "address_auths": [] } true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::get_custom_permissions(
    string owner)
When using the cli_wallet...
get_custom_permissions <owner>

name

data type

description

details

owner

string

The name or id of the account for which we'd like to see the list of created custom permissions.

n/a

get_custom_permissions account01
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::update_custom_permission(
    string owner,
    custom_permission_id_type permission_id,
    fc::optional<authority> new_auth,
    bool broadcast)
When using the cli_wallet...
update_custom_permissions <owner> <permission_id> <new_auth> true

name

data type

description

details

owner

string

The name or id of the account who is updating the permission.

n/a

permission_id

custom_permission_id_type

The ID of the custom permission we're intending to edit.

n/a

new_auth

authority

Just like create_custom_permission, this is a JSON object which represents an account authority.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

update_custom_permission account01 1.27.0 { "weight_threshold": 1,  "account_auths": [["1.2.53",1]], "key_auths": [], "address_auths": [] } true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::create_custom_account_authority(
    string owner,
    custom_permission_id_type permission_id,
    int operation_type,
    fc::time_point_sec valid_from,
    fc::time_point_sec valid_to,
    bool broadcast)
When using the cli_wallet...
create_custom_account_authority <owner> <permission_id> <operation_type> <valid_from> <valid_to> true

name

data type

description

details

owner

string

The name or id of the account who is creating the account authority.

n/a

permission_id

custom_permission_id_type

The ID of the custom permission we're intending to edit.

n/a

operation_type

int

This is the ID of any particular operation. IDs are available here.

n/a

valid_from

time_point_sec

The timestamp when the permission begins to be valid. See below for what a valid timestamp looks like.

n/a

valid_to

time_point_sec

The timestamp when the permission stops being valid. See below for what a valid timestamp looks like.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

create_custom_account_authority account01 1.27.0 0 "2019-11-22T18:30:00" "2020-12-03T17:53:25" true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::update_custom_account_authority(
    string owner,
    custom_account_authority_id_type auth_id,
    fc::optional<fc::time_point_sec> new_valid_from,
    fc::optional<fc::time_point_sec> new_valid_to,
    bool broadcast)
When using the cli_wallet...
update_custom_account_authority <owner> <auth_id> <new_valid_from> <new_valid_to> true

name

data type

description

details

owner

string

The name or id of the account who is updating the account authority.

n/a

auth_id

custom_account_authority_id_type

The ID of the custom account authority we're intending to edit.

n/a

new_valid_from

time_point_sec

The timestamp when the permission begins to be valid. See below for what a valid timestamp looks like.

n/a

new_valid_to

time_point_sec

The timestamp when the permission stops being valid. See below for what a valid timestamp looks like.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

update_custom_account_authority account01 1.28.0 "2020-06-02T17:52:25" "2020-06-03T17:52:25" true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::delete_custom_permission(
    string owner,
    custom_permission_id_type permission_id,
    bool broadcast)
When using the cli_wallet...
delete_custom_permission <owner> <permission_id> true

name

data type

description

details

owner

string

The name or id of the account who is deleting the permission.

n/a

permission_id

custom_permission_id_type

The ID of the custom permission we're intending to delete.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

delete_custom_permission account01 1.27.0 true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::delete_custom_account_authority(
    string owner,
    custom_account_authority_id_type auth_id,
    bool broadcast)
When using the cli_wallet...
delete_custom_account_authority <owner> <auth_id> true

name

data type

description

details

owner

string

The name or id of the account who is deleting the account authority.

n/a

auth_id

custom_account_authority_id_type

The ID of the custom account authority we're intending to delete.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

delete_custom_account_authority account01 1.28.0 true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::create_account_role(
    string owner_account_id_or_name,
    string name,
    string metadata,
    flat_set<int> allowed_operations,
    flat_set<account_id_type> whitelisted_accounts,
    time_point_sec valid_to,
    bool broadcast)
When using the cli_wallet...
create_account_role <owner_account_id_or_name> <name> <metadata> <allowed_operations> <whitelisted_accounts> <valid_to> true

name

data type

description

details

owner_account_id_or_name

string

The name or id of the account who is creating the account role.

n/a

name

string

The name of the account role. For example, "Movie Interstellar Permissions"

n/a

metadata

string

Metadata for additional info. For example, this could be a JSON object or and external URL with info.

n/a

allowed_operations

flat_set<int>

An array of numbers which represent all the operations that this role allows. IDs are available here.

n/a

whitelisted_accounts

flat_set<account_id_type>

An array of account IDs for the accounts that belong to this role and are therefore granted the allowed_operations for the resource.

n/a

valid_to

time_point_sec

The time at which the role no longer provides the allowed_operations to its whitelisted_accounts.

Note: valid_from is automatically set to the time the account role was created.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

create_account_role account01 ar1 ar1 [89,95] [1.2.40, 1.2.41, 1.2.43] "2020-09-04T13:43:39" true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::get_account_roles_by_owner(
    string owner_account_id_or_name)
When using the cli_wallet...
get_account_roles_by_owner <owner_account_id_or_name>

name

data type

description

details

owner_account_id_or_name

string

The name or id of the account for which we'd like to see the list of created account roles.

n/a

get_account_roles_by_owner account01
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::update_account_role(
    string owner_account_id_or_name,
    account_role_id_type role_id,
    optional<string> name,
    optional<string> metadata,
    flat_set<int> operations_to_add,
    flat_set<int> operations_to_remove,
    flat_set<account_id_type> accounts_to_add,
    flat_set<account_id_type> accounts_to_remove,
    optional<time_point_sec> valid_to,
    bool broadcast)
When using the cli_wallet...
update_account_role <owner_account_id_or_name> <role_id> <name> <metadata> <operations_to_add> <operations_to_remove> <accounts_to_add> <accounts_to_remove> <valid_to> true

name

data type

description

details

owner_account_id_or_name

string

The name or id of the account who is updating the account role.

n/a

role_id

account_role_id_type

The ID of the account role we're intending to update.

n/a

name

string

The name of the account role. For example, "Movie Interstellar Permissions"

n/a

metadata

string

Metadata for additional info. For example, this could be a JSON object or and external URL with info.

n/a

operations_to_add

flat_set<int>

An array of numbers which represent all the operations that should be added to the role. IDs are available here.

n/a

operations_to_remove

flat_set<int>

An array of numbers which represent all the operations that should be removed from the role. IDs are available here.

n/a

accounts_to_add

flat_set<account_id_type>

An array of account IDs for the accounts that should be added to the role.

n/a

accounts_to_remove

flat_set<account_id_type>

An array of account IDs for the accounts that should be removed from the role.

n/a

valid_to

time_point_sec

The time at which the role no longer provides the allowed_operations to its whitelisted_accounts.

Note: valid_from is automatically set to the time the account role was created.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

update_account_role account01 1.32.0 null null [88] [95] [1.2.42] [1.2.40] "2020-09-04T13:52:38" true
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::delete_account_role(
    string owner_account_id_or_name,
    account_role_id_type role_id,
    bool broadcast)
When using the cli_wallet...
delete_account_role <owner_account_id_or_name> <role_id> true

name

data type

description

details

owner_account_id_or_name

string

The name or id of the account who is deleting the account role.

n/a

role_id

account_role_id_type

The ID of the account role we're intending to delete.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

delete_account_role account01 1.32.0 true
Operation IDs here
custom permissions
Operation IDs here
Calculating Costs
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::create_asset(
    string issuer, 
    string symbol, 
    uint8_t precision, 
    asset_options common, 
    fc::optional<bitasset_options> bitasset_opts, 
    bool broadcast = false)
When using the cli_wallet...
create_asset <issuer> <symbol> <precision> <common> null true

name

data type

description

details

issuer

string

The name or id of the account who will pay the fee and become the issuer of the new asset. This can be updated later.

n/a

symbol

string

The ticker symbol of the new asset.

n/a

precision

uint8_t

The number of digits of precision to the right of the decimal point, must be between 0 and 12 (inclusive).

min 0, max 12

common

asset_options

Asset options required for all new assets. See section 1.4. Asset Options for details.

n/a

bitasset_opts

bitasset_options

Options specific to market issued assets. Put null here for a UIA. Put {} here for a market issued asset with the default price feed settings. Or you can price feed details here.

null for UIAs!

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

create_asset "1.2.18" "BTFUN" 8 {"max_supply" : 1000000000000000,"market_fee_percent" : 0,"max_market_fee" : 1000000000000000,"issuer_permissions" : 79,"flags" : 0,"core_exchange_rate" : {"base": {"amount": 1,"asset_id": "1.3.0"},"quote": {"amount": 1,"asset_id": "1.3.1"}},"whitelist_authorities" : [],"blacklist_authorities" : [],"whitelist_markets" : [],"blacklist_markets" : [],"description" : "BitFun token with precision 8"} null true
{
  "max_supply" : 1000000000000000,
  "market_fee_percent" : 0,
  "max_market_fee" : 1000000000000000,
  "issuer_permissions" : 79,
  "flags" : 0,
  "core_exchange_rate" : {
    "base": {
      "amount": 1,
      "asset_id": "1.3.0"
    },
    "quote": {
      "amount": 1,
      "asset_id": "1.3.1"
    }
  },
  "whitelist_authorities" : [],
  "blacklist_authorities" : [],
  "whitelist_markets" : [],
  "blacklist_markets" : [],
  "description" : "BitFun token with precision 8"
}
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::update_asset(
    string symbol, 
    optional<string> new_issuer, 
    asset_options new_options, 
    bool broadcast = false)
When using the cli_wallet...
update_asset <symbol> <new_issuer> <new_options> true

name

data type

description

details

symbol

string

The ticker symbol of the existing asset being updated.

n/a

new_issuer

string

If changing the asset’s issuer, the name or id of the new issuer. null if you wish to remain the issuer of the asset.

n/a

new_options

asset_options

The new asset_options object, which will entirely replace the existing options. See section 1.4. Asset Options for details.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

update_asset "BTFUN" null {"max_supply" : 1000000000000000,"market_fee_percent" : 50,"max_market_fee" : 1000000000000000,"issuer_permissions" : 79,"flags" : 0,"core_exchange_rate" : {"base": {"amount": 1,"asset_id": "1.3.0"},"quote": {"amount": 1,"asset_id": "1.3.1"}},"whitelist_authorities" : [],"blacklist_authorities" : [],"whitelist_markets" : [],"blacklist_markets" : [],"description" : "BitFun token for fun!"} true
{
  "max_supply" : 1000000000000000,
  "market_fee_percent" : 50,
  "max_market_fee" : 1000000000000000,
  "issuer_permissions" : 79,
  "flags" : 0,
  "core_exchange_rate" : {
    "base": {
      "amount": 1,
      "asset_id": "1.3.0"
    },
    "quote": {
      "amount": 1,
      "asset_id": "1.3.1"
    }
  },
  "whitelist_authorities" : [],
  "blacklist_authorities" : [],
  "whitelist_markets" : [],
  "blacklist_markets" : [],
  "description" : "BitFun token for fun!"
}
{
   "max_supply" : <number>
   "market_fee_percent" : <number>
   "max_market_fee" : <number>
   "issuer_permissions" : <number>,
   "flags" : <number>,
   "core_exchange_rate" : {
       "base": {
         "amount": <number>,
         "asset_id": "1.3.0"
       },
       "quote": {
         "amount": <number>,
         "asset_id": <this asset's ID>
       }
   },
   "whitelist_authorities" : [],
   "blacklist_authorities" : [],
   "whitelist_markets" : [],
   "blacklist_markets" : [],
   "description" : <string>
}

key

description

example value

max_supply

The maximum amount of this asset that can exist in circulation. This number is in Satoshi. So if you want a max supply of 100 tokens, and the asset has a precision of 2, the max_supply value should be 10000.

100.00 (100 tokens with precision of 2)

10000 (and remove the decimal point)

10000

market_fee_percent

If market fees of a UIA are turned on, fees have to be payed for each market transaction. The issuer can claim these fees. If the fee is set to 1%, the issuer will earn 1% of market volume as profit.

This is set in hundredths of one percent. So if you want 0.3%...

0.3% = 0.003

(hundredth of one percent) 100 / 0.01 = 10,000

0.003 * 10,000 = 30 (our value for the 0.3% fee we want)

30

max_market_fee

The maximum amount to charge for any market transaction. This is set in Satoshi as well.

If you want the max fee to be only 1 token...

1.00 (1 token with precision of 2)

100 (and remove the decimal point)

100

issuer_permissions

This represents the permissions available to the issuer of the asset. If any permission is ever set to false, that permission can never be set to true again. See the permissions & flags section below to learn how to set this number.

79

flags

This number represents the settings which correspond to the permissions available when setting the issuer_permissions. See the permissions & flags section below to learn how to set this number.

0

core_exchange_rate

This part of the options sets up the exchange rate between this new asset and PPY, the core asset of Peerplays. See the exchange rate section below to learn how to set this option.

a JSON object (see exchange rate section below)

whitelist_authorities

The white/blacklist authorities options allows you to list custom authorities. The whitelists and blacklists of accounts with these authorities are combined and serve as white/blacklists for the asset. This allows for easy outsourcing of KYC/AML verification to 3rd-party providers.

[issuer123, kycprovider]

blacklist_authorities

Same as whitelist_authorities.

[issuer123, kycprovider]

whitelist_markets

An issuer of a UIA may want to restrict trading pairs for their assets for legal reasons. You can chose to restrict trading pairs with white/blacklists.

[BTC, USDT]

blacklist_markets

Same as whitelist_markets.

[PPY]

description

A string that describes the asset.

"My fancy new token"

"charge_market_fee" = 0x01 (1)
"white_list" = 0x02 (2)
"override_authority" = 0x04 (4)
"transfer_restricted" = 0x08 (8)
"disable_force_settle" = 0x10 (16)
"global_settle" = 0x20 (32)
"disable_confidential" = 0x40 (64)
"witness_fed_asset" = 0x80 (128)
"committee_fed_asset" = 0x100 (256)
"core_exchange_rate" : {
       "base": {
         "amount": 21,           # denominator
         "asset_id": "1.3.0"     # PPY
       },
       "quote": {
         "amount": 76399,        # numerator
         "asset_id": "1.3.1"     # This new asset
       }
return type, namespace, & method
signed_transaction graphene::wallet::wallet_api::issue_asset(
    string to_account, 
    string amount, 
    string symbol, 
    string memo, 
    bool broadcast = false)
When using the cli_wallet...
issue_asset <to_account> <amount> <symbol> <memo> true

name

data type

description

details

to_account

string

The name or id of the account to receive the new shares.

n/a

amount

string

The amount to issue, in nominal units.

Example: 0.5 for half a token

symbol

string

The ticker symbol of the asset to issue.

n/a

memo

string

A memo to include in the transaction, readable by the recipient.

n/a

broadcast

bool

true or false, whether or not you want to broadcast the transaction.

n/a

issue_asset "myfriend1" 1000 "BTFUN" "Enjoy some BitFun, Friend!" true
AAVE
ADA
ALGO
AMP
ATOM
AVAX
BCH
BNB
BSV
BTCB
BTS
BUSD
CAKE
CRO
DAI
DOGE
DOT
EGR
EOS
ETC
ETH
FEI
FIL
FTT
HBD
HIVE
ICP
KLAY
LEO
LINK
LTC
LUNA
MATIC
MIOTA
MKR
NEO
SBD
SHIB
SOL
STEEM
TFUEL
THETA
TRX
UNI
USDC
USDT
UST
VET
WBNB
WBTC
XLM
XMR
XRP
XTZ
1.4. Asset Options
1.4. Asset Options
Calculating Costs
build (#467332251) · Jobs · PBSA / peerplaysGitLab
Logo