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...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This section contains pages that describe low level design
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...
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.
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:
API Libraries plays an important role in communicating with Peerplays blockchain. This section explains about:
Steps to install
How to create an account?
How to create a Peerplays wallet?
NFT, Marketplace, and Role based Permission API
Click the below link to learn about the API Libraries in detail.
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.
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.
This section explains about important Authentication techniques and random numbers:
Peer ID - Explain about Authentication and Requirement to create a Peer ID
Random Number Generator (RNG) - Explain about RNG Generation process and API involved in getting a random number.
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:
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.
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.
Peerplays Public Docs Portal - Click to land in Public documentation portal.
- Click to gather extensive knowledge about Peerplays.
- Click to understand the operation of Peerplays node.
The history API is available from the full node via websockets.
Get operations relevant to the specified account.
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 only asked operations relevant to the specified account.
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 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).
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.
Get details of order executions occurred most recently in a trading pair.
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 OHLCV data of a trading pair in a time range.
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 OHLCV time bucket lengths supported (configured) by this API server.
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.
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.
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 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.
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
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.
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 get_asset()
, accounts have get_account()
, but this function will work for any object.
id
: the id of the object to return
The requested object.
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.
Get grouped limit orders in given market.
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.
The wallet (cli_wallet
) requires a running full node to connect to because it does not offer P2P or blockchain capabilities directly.
The crypto API is available from the full node via websockets.
Get signed blocks.
Generates a Pedersen Commitment: *commit = blind * G + value * G2. The commitment is 33 bytes, the blinding factor is 32 bytes.
blind
: Sha-256 blind factor type
value
: Positive 64-bit integer value
A 33-byte Pedersen Commitment: commit = blind G + value * G2
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.
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.
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.
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
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
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.
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.
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.
Creates a new user-issued or market-issued 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.
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 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.
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 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.
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 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.
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
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.
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 new shares of an asset.
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
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.
asset_name_or_id
: the symbol or id of the BitAsset in question
The BitAsset-specific data for this asset
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.
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.
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.
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
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
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.
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
Returns a list of all commands supported by the wallet API.
A multi-line string suitable for displaying on a terminal.
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.
Returns info about head block, chain_id, maintenance, participation, current active witnesses and committee members.
Runtime info about the blockchain
Returns info such as client version, git version of graphene/fc, version of boost, openssl etc.
Compile time info and client and dependencies versions.
nodes
: Nodes to be added.
List of connected peers.
The network broadcast API is available from the full node via web-sockets.
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
trx
: The transaction to broadcast
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.
cb
: the callback method
trx
: the transaction
Broadcast a signed block to the network.
block
: The signed block to broadcast.
The database API is available from the full node via web-sockets.
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.
Register a callback handle which then can be used to subscribe to object database changes.
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.
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.
cb
: The callback handle to register
Register a callback handle which will get notified when a block is pushed to database.
cb
: The callback handle to register
Stop receiving any notifications.
This unsubscribes from all subscribed markets and objects.
Retrieve a block header.
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
Retrieve a full, signed block.
block_num
: Height of the block to be returned
The referenced block, or null if no matching block was found.
Fetch an individual transaction.
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.
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.
Retrieve compile-time constants.
Get the chain ID.
Get all accounts that refer to the specified public keys in their owner authority, active authorities or memo key.
keys
: a list of public keys to query
ID of all accounts that refer to the specified keys.
Get a list of accounts by names or IDs.
account_names_or_ids
: names or IDs of the accounts to retrieve
The accounts corresponding to the provided names or IDs.
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.
names_or_ids
: Each item must be the name or ID of an account to retrieve
Map of string from names_or_ids
to the corresponding account.
Get info of an account by name.
name
: Name of the account to retrieve
The account holding the provided name.
Get all accounts that refer to the specified account in their owner or active authorities.
account_name_or_id
: Account name or ID to query
All accounts that refer to the specified account in their owner or active authorities
Get a list of accounts by name.
account_names
: Names of the accounts to retrieve
The accounts holding the provided names.
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.
lower_bound_name
: Lower bound of the first name to return
limit
: Maximum number of results to return must not exceed 1000
Map of account names to corresponding IDs.
Get the total number of accounts registered with the blockchain.
Get an account’s balances in various assets.
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.
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.
addrs
: a list of addresses
All unclaimed balance objects for the addresses.
Calculate how much assets in the given balance objects are able to be claimed at current head block time.
objs
: a list of balance object IDs
A list indicating how much asset in each balance object is available to be claimed.
Return all vesting balance objects owned by an account.
account_name_or_id
: name or ID of an account
All vesting balance objects owned by the account.
Get a list of assets by symbol names or IDs.
asset_symbols_or_ids
: symbol names or IDs of the assets to retrieve
The assets corresponding to the provided symbol names or IDs.
Get assets alphabetically by symbol name.
lower_bound_symbol
: Lower bound of symbol names to retrieve
limit
: Maximum number of assets to fetch (must not exceed 101)
The assets found.
Get a list of assets by symbol names or IDs.
symbols_or_ids
: symbol names or IDs of the assets to retrieve
The assets corresponding to the provided symbols or IDs
Returns the order book for the market base
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 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 (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 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.
Get all open margin positions of a given account.
account_name_or_id
: name or ID of an account
All open margin positions of the account.
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
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 updates to a given market.
a
: symbol name or ID of the first asset
b
: symbol name or ID of the second asset
Returns the ticker for the market assetA:assetB.
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.
Returns the 24 hour volume for the market assetA:assetB.
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.
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.
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
Get a list of witnesses by ID.
witness_ids
: IDs of the witnesses to retrieve
The witnesses corresponding to the provided IDs.
Get the witness owned by a given account.
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.
Get names and IDs for registered witnesses.
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 the total number of witnesses registered with the blockchain.
Get a list of committee_members by ID.
committee_member_ids
: IDs of the committee_members to retrieve
The committee_members corresponding to the provided IDs.
Get the committee_member owned by a given account.
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.
Get names and IDs for registered committee_members.
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
Get the workers owned by a given account.
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.
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
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.
Get a hexdump of the serialized binary form of a transaction.
trx
: a transaction to get hexdump from
The hexdump of the transaction.
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.
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.
trx
: the transaction to be signed
A set of public keys that could possibly sign for the given transaction.
This method will return the set of all addresses that could possibly sign for a given transaction.
trx
: the transaction to be signed
A set of addresses that could possibly sign for the given transaction.
Check whether a transaction has all of the required signatures
trx
: a transaction to be verified
true if the trx
has all of the required signatures, otherwise throws an exception.
Verify that the public keys have enough authority to approve an operation for this account.
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.
Validates a transaction against the current state without broadcasting it on the network.
trx
: a transaction to be validated
A processed_transaction object if the transaction passes the validation, otherwise an exception will be thrown.
For each operation calculate the required fee in the specified asset type.
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
Gets a set of proposed transactions (proposals) that the specified account can add approval to or remove approval from.
account_name_or_id
: The name or ID of an account
A set of proposed transactions that the specified account can act on.
Gets the set of blinded balance objects by commitment ID.
commitments
: a set of commitments to query for
The set of blinded balance objects by commitment ID.
If you have not set up your wallet yet, you can find more information here: .
Tip: For more information about Pedersen Commitment see:
Many options can be changed later using .
See
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 .
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 to claim collateral instantly at the settle price from the pool.
This lists each command, along with its arguments and return types. For more detailed help on a single command, use .
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 )
The objects retrieved, in the order they are mentioned in ids.
Note: auto-subscription is enabled by default and can be disabled with
Retrieve the associated with the chain.
Retrieve the current .
Retrieve the current .
This function has semantics identical to ****
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 )
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 )
This function has semantics identical to, but doesn’t subscribe
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 ).
Semantically equivalent to .
Semantically equivalent to .
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 )
Semantically equivalent to , but doesn’t subscribe.
Similar to , but without pagination.
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 to query for the rest.
Semantically equivalent to , but doesn’t subscribe.
Semantically equivalent to , but doesn’t subscribe.
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 to get the minimum subset.
Returns info about a specified block.
num
: height of the block to retrieve
Info about the block, or null if not found.
Returns the number of accounts registered on the blockchain.
The number of registered accounts
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 get_dynamic_global_properties()
for frequently changing properties.
The 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 get_global_properties()
for less-frequently changing properties.
The dynamic global properties.
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 get_asset()
, accounts have get_account()
, but this function will work for any object.
id
: the id of the object to return.
The requested object.
Creates a committee_member object owned by the given account.
An account can have at most one committee_member object.
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
Returns information about the given witness.
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.
Returns information about the given committee_member.
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
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.
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
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.
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
Creates a witness object owned by the given account.
An account can have at most one witness object.
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 a witness object owned by the given account.
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 a worker object.
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 your votes for workers.
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 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.
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 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.
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 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.
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 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.
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
Creates a transaction to propose a parameter change.
Multiple parameters can be specified if an atomic change is desired.
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 a fee change.
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
The network node API is available from the full node via web-sockets.
Return general network information, such as p2p port.
Get status of all current connections to peers.
Return list of potential peers.
Get advanced node parameters, such as desired and max number of connections.
Connect to a new peer
ep
: The IP/Port of the peer to connect to
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
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.
key
: a public key
label
: a user-defined string as label
True if the label was set, otherwise false
Get label of a public key.
Get the public key associated with a given label
label
: a label
The public key associated with the given label.
Get all blind accounts.
All blind accounts
Get all blind accounts for which this wallet has the private key.
All blind accounts for which this wallet has the private key.
Return the total balances of all blinded commitments that can be claimed by the given account 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
Generates a new blind account for the given brain key and assigns it the given label
label
: a label
brain_key
: the brain key to be used to generate a new blind account
The public key of the new account
Transfers a public balance from from_account_id_or_name
to one or more blinded balances using a stealth transfer.
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
Transfers funds from a set of blinded balances to a public account balance.
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.
Transfer from one set of blinded balances to another.
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
Get all blind receipts to/form a particular account.
key_or_account
: a public key in Base58 format or an account
All blind receipts to/form the account.
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.
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.
Lists all accounts controlled by this wallet. This returns a list of the full account objects for all accounts whose private keys we possess.
A list of account objects
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.
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 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.
id
: the name or id of the account whose balances you want
A list of the given account’s balances
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.
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
Upgrades an account to prime status. This makes the account holder a ‘lifetime member’.
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
Creates a new account and registers it on the blockchain.
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 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, 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
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 (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 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.
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 information about a vesting balance object or vesting balance objects owned by an account.
account_name
: An account name, account ID, or vesting balance object ID.
A list of vesting balance objects with additional info
Withdraw a vesting balance.
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
Returns information about the given account.
account_name_or_id
: the name or ID of the account to provide information about
The public account data stored in the blockchain
Lookup the id of a named account.
account_name_or_id
: the name or ID of the account to look up
The id of the named account
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
Approve or disapprove a proposal.
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
Subscribe a listener to a betting market.
updateListener
: An object of type updateListener.
1.3.0:
Start version.
1.3.19:
End version.
Unsubscribe a listener from a betting market.
updateListener
: An object of type updateListener.
1.3.0:
Start version.
1.3.19:
End version.
Introduction
Its the Python library for communicating with the Peerplays blockchain.
1.2.x : accounts
1.3.x : assets
p.rpc.get_account_balances("jemshid", [])
p.rpc.get_global_properties
private-key = ["TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]
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 an asset or update the debt/collateral ratio for the loan.
This is the first step in shorting an asset.
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 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
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 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 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 (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 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
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.
True if the wallet is new.
Checks whether the wallet is locked (is unable to use its private keys).
True if the wallet is locked
Locks the wallet immediately.
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.
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.
password
: a new password
Dumps all private keys owned by the wallet.
A _**_map containing the private keys, indexed by their public 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.
account_name_or_id
: the account owning the key
wif_key
: the private key in WIF format
true if the key was imported
Imports accounts from a BitShares 0.x wallet file. Current wallet file must be unlocked to perform the import.
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.
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.
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
This call will construct transaction(s) that will claim all balances controlled by wif_keys and deposit them into the given account.
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
This function will suggest a suitably random string that should be easy to write down (and, with effort, memorize).
A suggested brain_key
This method is used to convert a JSON transaction to its transacting ID.
trx
: a JSON transaction
The ID (hash) of the transaction.
Get the WIF private key corresponding to a public key. The private key must already be in the wallet.
pubkey
: a public key in Base58 format
The WIF private key
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()
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.
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.
s
: the brain key as supplied by the user
The brain key in its normalized form.
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.
wallet_filename
: the filename of the new wallet JSON file to create or overwrite. If wallet_filename
is empty, save to the current filename.
Create a new transaction builder.
Handle of the new transaction builder.
Append a new operation to a transaction builder.
transaction_handle
: handle of the transaction builder
op
: the operation in JSON format
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
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.
Show content of a transaction builder.
handle
: handle of the transaction builder
A 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.
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
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.
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.
Destroy a transaction builder.
handle
: handle of the transaction builder
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
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
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.
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.
key
: a public key
The label if already set by , or an empty string if not set
See also ****
See also , ****
The code is maintained at
Call to complete the short.
This state can be changed by calling or .
password
: the password previously set with
The keys are printed in WIF format. You can import these keys into another wallet using
See also **
Suggests a safe brain key to use for creating your account. requires you to specify a ‘brain key’, a long passphrase that provides enough entropy to generate cryptographic keys.
Note: this command is not effective because you're unable to specify a proposer. It will be deprecated in a future release. Use instead.
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.
The python-peerplays library has following dependencies. Make sure that the above dependencies are installed, if not install with:
Now install python-peerplays as follows:
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 git@gitlab.com:PBSA/PeerplaysIO/tools-libs/python-peerplays.git
cd python-peerplays
git checkout develop
API Calls for Non Fungible Tokens
For example
For example
For example
For example
For example
For example
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)
For examples, refer to tests/test_nft.py
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.
password = "password"
from peerplays import PeerPlays
To create a new wallet
p.newWallet(password)
Unlock the wallet
p.unlock(password)
Add private key / keys
p.wallet.addPrivateKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")
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.
There are two ways to create an account.
With Python-Peerplays: If you already have an account, it can be used to create another account.
With the Faucet: To create an account without an existing account.
You need a funded account to create additional accounts. The funded account should be upgraded to create new accounts. To upgrade an account
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')
url =
https://mint-faucet.peerplays.download/
requests.post(url, json=params)
Get a list of tournament ids for upcoming tournaments
stateString
: The tournament state
accountId
:Account Id
All tournaments for the selected state.
Get a list of registered tournaments by account id.
accountId
: Account Id.
All registered tournaments for an account.
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
.
This page documents the BookiePro data abstraction layer with the Peerplays blockchain.
BookiePro communicates with the blockchain using web-socket API calls.
Get a list of available sports.
A list of all the available sports.
Get a list of all event groups for a sport, for example, all soccer leagues in soccer.
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.
Get a list of all betting market groups for an event, for example, Moneyline and OVER/UNDER for soccer)
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.
Get a list of all betting markets for a betting market group (BMG).
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.
Get global betting statistics
A list of all the global betting statistics.
Get the binned order book for a betting market.
betting_market_id:
The id of the betting market for the order book.
precision:
Precision
A list of binned orders for the betting market.
Get the total matched bets for a betting market group (BMG).
group_id
: The betting market group id.
Total of all the matched bet amounts for the selected betting market group.
Used to search for events.
sub_string:
The (sub) string of text to search for
language
: Language id.
List of events that contain the sub-string
Get unmatched bets for a bettor.
bettor_id
: The id of the bettor.
List of all matched bets for a bettor.
Get a list of events in any event group.
event_group_id
: The id of the event group.
A list of all the events in the event group.
Get all unmatched bets of a bettor according to account type.
account_type_id
: The id of the bettor account type/
All unmatched bets by bettor account type.
Get the matched bets for a bettor.
bettor_id
: The id of the bettor.
All matched bets for the bettor.
Get all matched bets for a bettor within a range.
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.
A guide to create UIAs, also known as Fan Tokens or Community Asset Tokens (CATs).
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.
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.
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:
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
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
In this example call we used the following settings for the common
parameter:
Please see section 1.4. Asset Options 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.
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!
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:
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
n/a
broadcast
bool
true
or false
, whether or not you want to broadcast the transaction.
n/a
In this example call we used the following settings for the common
parameter:
Please see section 1.4. Asset Options 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!
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.
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"
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.
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.
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.
Issues new shares of an asset that exists via create_asset
.
The basic structure of the issue_asset
function looks like this:
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
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.
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.
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.
configure the config/default.json
and config/development.json
files:
default.json
development.json
Start the application:
Asset options required for all new assets. See section for details.
The new asset_options object, which will entirely replace the existing options. See section for details.
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.
Enter a name or path for the parameter.
Optionally add a description.
Select the tier to use.
Select the type. (we will choose SecureString.)
Select the KMS key source which is what will encrypt the SecureString.
Enter the value for the parameter.
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 a policy with permissions for KMS and SSM:
Choose the service Elastic Container Service
Select the use case as Elastic Container Service Task
Attach the policy created to read secrets from Parameter Store.
Enter a role name.
Enter a role description.
API Calls for Role Based Permissions (RBPs)
How communities can get work done. An example dapp idea using Peerplays.
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.
This concept will make use of some Peerplays components:
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
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:
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.
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.
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.
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.
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.
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:
Use the get_global_properties
function. Copy the whole list of operation IDs/fees from the return.
Download the latest copy of the Operation ID mapping.
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.
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.
Calling this function is simple:
The global_property_object
is returned:
Parts of the example return have been truncated to fit. The actual return is much longer.
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:
Operation #85 -> custom_account_authority_create_operation
-> Fee = 0.005 PPY & Kb of Data = 0.01 PPY
Operation #92 -> nft_metadata_create_operation
-> Fee = 0.1 PPY & Kb of Data = 0.01 PPY
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!
A guide for creating NFTs from start to finish.
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.
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.
The basic structure of the nft_metadata_create
function looks like this:
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.
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.
First we create the permission:
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:
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.
This function updates an existing NFT metadata object.
The basic structure of the nft_metadata_update
function looks like this:
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.
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.
The basic structure of the nft_create
function looks like this:
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.
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.
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.
Or...
The basic structure of the nft_transfer_from
and nft_safe_transfer_from
function looks like this:
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.
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.
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.
After creating the Task Definition, we can now create a Cluster.
Select the Networking only
cluster template.
Enter the cluster name.
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:
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.
Create NAT gateways for the public facing subnets.
Create route tables for the private subnets and add a 0.0.0.0/0 routes to the NAT gateways.
Once we have created a Cluster, we can create a service inside it.
Choose a Launch Type. (In this case we will be using FARGATE).
Select a Task Definition and revision.
Select the platform version.
Select a cluster.
Create a name for the service.
Select the service type (in this case we will be using REPLICA).
Enter the number of tasks that the service should try to keep running.
Enter the desired value for the minimum and maximum healthy percent.
Select either the Rolling update or Blue/green deployment.
Select a placement strategy from the placement templates.
Select your Cluster VPC.
Select your desired subnets.
Attach security groups.
Attach a Load Balancer
Select Service Auto Scaling to set the cardinality of tasks and automatic task scaling policies.
{
"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:
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
.
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
}
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.
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
}
The two ways of deployment are explained in the documents below:
The below sections help in understanding the ways of deployment and development.
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 created from Storing Secrets in Amazon Parameter Store to use in ECS.
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.
We can assign total memory and CPU to the task. For PeerID, choose:
2GB Task Memory (GB)
1 vCPU Task CPU (vCPU)
Create two containers:
PeerID Backend
PeerID Frontend + Webserver (we will be using NGINX)
Enter the container name.
Enter the path to the Docker registry with the container Image.
Enter 1024
for a soft limit for the memory.
Enter 3000
tcp for the port mappings.
Enter 756
CPU units.
Tick the essential box.
Enter /peerid-backend/docker-entrypoint.sh
for the entry point.
Enter npm,run,start
for the command.
Enter peerid-backend
for the working directory.
Enter the environment variables for PeerID Backend using ValueFrom
and referencing the parameters from Systems Manager Parameter Store.
PeerID Frontend
Enter the container name.
Enter the path to the Docker registry with the container Image.
Enter 256
for a soft limit for the memory.
Enter 80
and 443
tcp for the port mappings.
Enter 256
CPU units.
Tick the essential box.
Enter /docker-entrypoint.sh
for the entry point.
Enter nginx,-g,daemon off;
for the command.
Enter the environment variables for PeerID GUI using ValueFrom
and referencing the values created from Systems Manager Parameter Store.
A brief explanation of role-based & resource permissions for Peerplays objects.
There are three functions available in the CLI Wallet to produce permission settings:
create_custom_permission
create_custom_account_authority
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.
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 Operation IDs here.
This function creates a new custom permission.
The basic structure of the create_custom_permission
function looks like this:
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
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.
This function returns the custom permissions that have been created by the given account.
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:
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
n/a
broadcast
bool
true
or false
, whether or not you want to broadcast the transaction.
n/a
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.
Creating a custom authority maps the created custom permissions 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:
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
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
A valid timestamp looks like this: "2019-11-22T18:30:00"
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
.
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:
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
A valid timestamp looks like this: "2019-11-22T18:30:00"
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:
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
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:
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
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 Operation IDs here.
This function creates an account role.
The basic structure of the create_account_role
function looks like this:
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>
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
A valid timestamp looks like this: "2020-09-04T13:43:39"
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
.
You can use this to find all the account roles by their owner.
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:
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>
n/a
operations_to_remove
flat_set<int>
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
A valid timestamp looks like this: "2020-09-04T13:43:39"
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.
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:
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
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.
The following documents help to understand the requirements and authentication process of PeerID:
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.
Every account that’s created on Peerplays has two default permissions by default.
Owner
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.
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.
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.
Just like , this is a JSON object which represents an account authority.
This is the ID of any particular operation. IDs are .
An array of numbers which represent all the operations that this role allows. IDs are .
An array of numbers which represent all the operations that should be added to the role. IDs are .
An array of numbers which represent all the operations that should be removed from the role. IDs are .
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.
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:
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).
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.
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:
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.
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.
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:
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.
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.
For more information on the API see the RNG API.
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:
Registering your app to obtain a client ID and client secret. This includes specifying scopes (permissions) your app requires.
Getting an access token for the PeerID user. This includes the user authorizing your app using their login credentials.
Sending the token in your API request to perform an operation on the Peerplays blockchain on behalf of the user.
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!
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:
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>
:
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.
If the user authorizes your application, the user is redirected to your redirect URL:
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.
On your server, get an access token by making this request:
We respond with a json-encoded access token. The response looks like this:
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:
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:
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
.
We respond with a json-encoded access token. The response looks like this:
Store the access token and refresh token like passwords.
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:
The access token for one app cannot be used for another app.
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:
The response will look like this:
Once again, store the access token and refresh token like you would a password.
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.
Created by [Bobinson Bobby]
Facilitator
@Bobinson Bobby
Participants
@Prabhjot Singh @Satyanarayana Koneru
Brainstorm date
Jun 11, 2020
Video conference link
On this page
Goals of the brainstorm
Finalize the requirements for the Identify provider
Participant instructions
Compare existing Identity / SSO providers
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.
For a user with Twitch/Facebook account, it should be easy to sign up for a Peerplays account
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.,
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
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!
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
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.
Command:
References:
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.
Start
bitcoind
in regtest mode to create a private block chain.
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.
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 theregtest
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:
Command:
References:
Command Definition:
Command Structure:
Command Example:
Reference:
One can use Curl command or POSTMAN in order to create a new account in the Faucet. With Curl you can do the following:
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:
And in case of any error, it will be following (i.e. duplicate account):
You can also track the logs in Faucet container, with the following command:
And look for logs when receiving Create Account requests, with 200 status code as a result.
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:
IP_ADDRESS should be 127.0.0.1 or localhost when running it directly on your local machine.
In the QA environment setup by instructions in here, execute commands in Peerplays01 container with the following:
Then running into account’s wallet:
Unlock the wallet with the default password (which is "password"):
Get the private key for active key (public key):
ACCOUNT_PASSWORD is the password defined when creating account in DEX UI.
Import the private key returned from previous step:
Finally transfer with the following:
memo key should be empty string for it to work. With list_core_accounts command you can check all account’s balances.
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.
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.
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.
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
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.
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.
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.
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.
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
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
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
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 pbsa.info.
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.
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.
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.
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
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.,
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.
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.
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
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.,
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
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
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
Requirements specification for Peerplays SONs
Provide bi-directional exchange of value (tokens/coins) between multiple chains and Peerplays
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
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.
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.
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)
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.
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
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.
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.
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.
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
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.
TBD
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.
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
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
Provide requirements for Sidechain Operating Nodes (SON). PIP (Peerplays Improvement Proposal) for the same is here :
For general information on deposit handlers, read:
Link to file
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.
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.
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.
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.
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.
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
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:
All pre-maintenance are to be considered invalid after maintenance.
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.
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:
Invalid serialization of a Bitcoin transaction.
Bitcoin transaction uses invalid signatures.
Bitcoin transaction uses invalid vin.
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.
vins are checked for validity via bitcoin_rpc_client::receive_confirmations_tx.
All invalid vins are dropped.
All valid vins and vouts are added to btc_revert_operation and sent to the blockchain.
Transaction object is removed from sidechain_net_manager::bitcoin_confirmations.
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.
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`.
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
This doc describes the required changes to Bitcoin multisignature wallet scripting mechanism (previously described in Multisignature wallet LLD).
TODO
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:
All pre-maintenance are to be considered invalid after maintenance.
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 : Functional Specification - SONs switchover scenarios#SONsswitchoverscenarios-6.Scenarios
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:
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
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).
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:
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
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.
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:
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
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).
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:
ChainTypes.js
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
Add the following missing implementation object types to the impl_object_type
constant: son_statistics: 24, son_schedule: 25
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
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
}
);
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
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'))
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', {});
Add 'son' to vesting_balance_type
enum serializer: const vesting_balance_type = enumeration([ 'normal', 'gpos', 'son' ]);
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')
});
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
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.
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.
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
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.
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.
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.
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.
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.
This document is intended to outline generic design of a blockchain handler, a component used for monitoring and processing changes on a Bitcoin network.
Same sequence diagram applies for all sidechain handlers. It shows interactions between components in a single sidechain handler.
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.
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.
There is a libzmq3-dev package in Ubuntu 18.04 repository.
This will be obvious developers choice, for ease of installation and usage.
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
Method to retrieve the transaction by hash
Method to retrieve block as json
HTTP request to "http://ip/:PORT/rest/block/BLOCK_HASH.json"
Method to decode transaction
Method to retrieve the transaction fee
Method to send signed transaction to the node (for deposit/withdrawal)
Communication interface can be implemented as a HTTP client, which will send requests to a bitcoin node.
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
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)
This document assumes that the multi-signature wallet is existing
This document is intended to outline generic design of a Bitcoin withdrawal handler, a component used for processing withdrawals to Bitcoin network.
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
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
For general information on sidechain handlers, read:
Link to file:
Link to file
For general information on sidechain listeners, read:
Some of the info in this section are taken from useful article on ZMQ and Bitcoin
For general information on deposit handlers, read:
Link to file
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.
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.
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.
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.
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.
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.
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.
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.
To be done on the basis of the implementation chosen.
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.
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.
Link to draw.io file
https://drive.google.com/file/d/14HFGLqD8IV3ics1ojFcZ2xC6hRtFXLck/view?usp=sharing
As described in Generic Sidechain High Level Design , 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: https://github.com/bitshares/bitshares1-core/wiki/multisig
All sidechain specific functionalities will be implemented in sidechain handler.
All general functionalities will be implemented in sidechain handler base class.
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.
The purpose of this document is to provide the design for the SON configuration.
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.
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).
Described here is the design for configuring the SONs on a node
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 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.
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.
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.
This document is intended to outline generic design of a blockchain listener, a component used for monitoring changes on a target blockchain.
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.
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
Link to draw.io file:
https://drive.google.com/file/d/1ErmQfeaWa9m67si4hb0RZs54WVYWR0pC/view?usp=sharing
Link to draw.io file
https://drive.google.com/file/d/17kbez7C1Djaj-2AgyEzQ1Z-5CrSZ5wZE/view?usp=sharing
Sequence diagram shows sidechain listener interactions with the rest of the sidechain components.
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.
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.
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.
Link to draw.io file
https://drive.google.com/file/d/1qSWvcxfWVEwJV2nZA-xTApTSi5rH_1uv/view?usp=sharing
The withdrawal is initiated by user, by transfering Peerplays core asset to SON shared account.
As described in Generic Sidechain High Level Design , 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: https://github.com/bitshares/bitshares1-core/wiki/multisig
All sidechain specific functionalities will be implemented in sidechain handler.
All general functionalities will be implemented in sidechain handler base class.
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.
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.
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
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
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.
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.
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…
Link to Draw.io file
https://drive.google.com/file/d/1BXeRwK_2PNt6wMnzIl8M6OMRnuM5CumQ/view?usp=sharing
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.
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.
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
The purpose of this document is to provide low-level design for making payments to SONs for their contribution to the Peerplays network.
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.
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.
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.
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.
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.
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.
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.
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.
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.
This parameter is used to specify the current son max payout.
It can be re-configured by committee_member_update_global_parameters_operation.
This parameter is used to denote the son_budget till next payout interval.
This is set every payout interval.
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.
This function should be introduced and called from perform_chain_maintenance.
After this new budget should be recorded and saved.
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
The following dependencies are necessary for a clean Ubuntu 18.04 LTS
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:
To unpack executables in current folder:
Execute the witness_node
binary which will create the necessary files and folders under witness_node_data_dir
Stop the node (CTRL + c
) and edit config.ini
to configure the node.
Inside config.ini
, set the seed-nodes
to:
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
Move the genesis.json
file to the root of the project directory alongside the witness_node
binary.
Inside config.ini
, specify the genesis.json
Start the witness_node
and the blocks should start syncing.
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.
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.
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)
SON plugin is controlled by following parameters
These parameters are available from both command line and config file:
Edit add the following to your config.ini file
Edit the config file and add the RPC port
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:
In the terminal execute the 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:
There is optionally a flag that can be passed in to connect to a remote rpc endpoint.
Enter a password for the CLI wallet:
Unlock the CLI wallet by providing the password set earlier:
The CLI wallet will show unlocked >>>
when successfully unlocked
The CLI wallet is now ready to be used.
Use the CLI wallet to suggest a brain key:
Make sure to backup the information that is output
Create an account using the brain key generated:
The purpose of this document is to provide a low-level design for implementing list_sons wallet functionality.
The design requirement listed in this document will be limited to the SON Wallet functionality.
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.
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.
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.
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 ).
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.
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
All the new data structures and helper functions can be found in the UML diagram below.
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.
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.
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.
This section tries to disambiguate the types of users registered on the current system and their roles.
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.
Workers are the group of users who maintain the network and introduce new features into the network.
Committee members are the unpaid volunteers that organize the community and propose changes to the network.
PPY Holders are regular users who hold PPY in their accounts.
They can cast a vote and influence the decisions of the network.
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)
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.
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.
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,
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.
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.
This class is used to update an already created son object in DB.
This class is used to delete an already created son object in DB.
This class contains do_evaluate and do_apply functions which evaluate and apply the create operation respectively.
do_apply creates son_object in DB.
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.
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.
A new vote type son is introduced which is needed in vote_for_son flow.
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.
Following are the CLI Wallet commands to realize the functionality shown above,
More on SON Objects can be found at
All the info related to proposals can be found at
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. Done
./programs/witness_node/witness_node --resync --replay --son_enable
The command enables the SON functionality in the node
create_son <account_name> <proposal_url> true
The command registers the node on-chain and creates an ID
list_sons
The command lists all the account names that own SONs, active or inactive
vote_for_son <voting_account> <son_account> <approve> <broadcast>
The command allows voting in or out for a given SON account
update_son <son_account> <proposal_url> <signing_key> <broadcast>
The command updates the created SON Object related to the SON account given
remove_son <son_account> <broadcast>
The command marks the SON Node as delete on-chain
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.
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.
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.
As proposed and implemented in GPOS, user can vest a certain amount to,
Participate in voting for proposals.
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.
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.
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.
Currently, there are two types of vesting policies are in place,
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.
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.
An SON can be deregistered in two ways according to the functional requirements,
remove_son called for SON in any state by the user from the wallet.
If an active SON is in maintenance for more than 12 hours.
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.
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.
A new vesting_balance_type son is introduced like the one similar to gpos.
This helps in identifying the type of vesting amount.
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.
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.
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.
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.
remove_son takes precedence and the node is deregistered at the next maintenance interval.
The new dormant vesting policy is activated.
TODO: This should be specified in the FR Document.
The first timestamp when the SON initially de-registered takes precedence.
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).
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.
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.
There are two types of bitcoin addresses,
PW Address
Deposit Address of a User.
Following are the list of steps needed for a user to transfer BTC,
A PW Address is created which acts as a global address holding all the user funds.
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.
The user transfers BTC funds to the deposit address.
Bitcoin block listener catches the transaction if any vout has any of the deposit addresses.
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.
After receiving confirmation from Bitcoin ( 6 blocks confirmation ) a proposal to issue pBTC to the user's account is initiated by SONs.
If the proposal is approved, pBTC is issued to the user's peerplays account.
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.
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.
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.
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.
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.
PW multi-sig address might need to be changed multiple times in this model because of the weights.
Loss of miners fee associated with the transfer of BTC from old PW address to new PW address.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
The purpose of this document is to provide low-level design for the communication mechanism between SONs and transaction signing.
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.
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.
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.
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,
Transferring BTC to User address after withdrawal.
Transferring BTC from old PW to new PW.
To issue pBTC.
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,
Create a peerplays account for a sidechain SON-195 - Getting issue details... STATUS , let's name it ‘son-btc-account’.
Owners for the account are SONs.
Weights of their signatures are proportional to the votes they receive.
The weight threshold of the account is 2/3 of the total weight.
Any operation related to the SON tasks has the paying account as the son account that's created.
All such operations are encapsulated in proposals.
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 );
});
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
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,
A Proposal is created with the fee-paying account as the individual SON account who is proposing.
Create the BTC raw transaction.
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).
Encapsulate the send operation in the proposal created.
Ensure the proposal lifetime is sufficient ( N*(number of SONs)*(block_creation_interval) where N is configurable i.e. 1,2,3,4 etc).
Publish the proposal on to the peerplays blockchain.
Each SON after receiving the proposal validated the data against the sidechain BTC database stored in the plugin locally.
If appropriate, each SON signs the BTC transaction.
Create a BTC Transaction Sign Operation with fee payer as the individual SON account who is signing (i.e. SON1 account, SON2 account, etc).
Sign the BTC transaction and store the signature in the sign operation.
Encapsulate the operation in a peerplays transaction, sign it and send it to peerplays blockchain.
The sign operation is evaluated by checking the SON signature on BTC Transaction with the SON public key registered on peerplays blockchain.
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.
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;
}
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;
});
}
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);
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.
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)
A bitcoin_issue_operation is created for which the fee-paying account is set to son-btc-account.
The issue operation is encapsulated in the proposal and sent to the peerplays blockchain.
Rest of the active SONs validate their plugin BTC databases and add approvals upon receiving the proposal.
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);
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.
We can retain most of the implementation from the sidechain branch.
It can be found here.
We can retain most of the implementation from the sidechain branch.
It can be found here.
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 );
});
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.
The purpose of this document is to provide low-level design for SON Voting mechanism.
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.
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.
More on SON Objects can be found at SON Objects and Operators
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.
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.
The purpose of this document is to provide a low-level design for the creation of a multi-signature bitcoin address.
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.
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.
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.
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.
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.
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.
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.
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.
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
a public key that, when hashed, yields destination address embedded in the script, and
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.
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.
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.
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,
Execute scriptSig which creates stack
Copy stack to stackCopy
Execute scriptPubKey using stack
If P2SH, replace stack with stackCopy
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.
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,
Pop n off of the stack (number of public keys)
Pop n public keys off of the stack.
Pop m off of the stack (number of required signatures)
Pop m signatures off of the stack.
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.)
Loop through all of the public keys, starting with the keys at the top of the stack.
For each public key, check a single signature.
For the first public key checked, start with the signature closest to the top of the stack.
If it fails to verify, go to the next public key and check the same signature.
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.
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.
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.
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.
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.
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 here.
The purpose of this document is to provide the design for the commands to be added to the CLI Wallet for SONs.
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.
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.
Described here is the design for commands to be added to the CLI Wallet for adding/removing SON, voting for SON, etc.
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.
The purpose of this document is to outline the steps required to pay the SONs for their contribution to the Peerplays network.
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.
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.
Described here is the process to pay the SONs on the Peerplays Blockchain.
N/A
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.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):
Core asset transaction fees are deducted from payer's account
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.
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.
configure witness_pay_per_block chain parameter = 1
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)
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.
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.
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 }
list_account_balances <sonaccount01> to check that the pay is added to the SON account’s balance.
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
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.
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.
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.
Described here is the process to vote for SONs in the Peerplays Blockchain.
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.
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
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.
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.
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.
Described here is the process to configure the SON plugin in the Peerplays blockchain.
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.
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.
./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.
The error messages are to be displayed in GUI wallet or cli_wallet or other programmatic means.
The SON node should not be enabled and active for the same Peerplays account
Trying to enable an already in enabled SON node will give the error message "SON is already enabled for the account_name."
The account trying to enable SON should have a minimum balance of 50 PPY which has to be VESTED to become SON
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"
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.
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.
The error messages are to be displayed in GUI wallet or cli_wallet or other programmatic means.
Only a SON node which is in "enabled state" can be disabled
Trying to de-activate/disable a Peerplays node with SON not enabled will give the error message "SON is not enabled for account_name"
If a SON is disabled and trying to move the VESTED funds before 2 days duration via any means should be prevented
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:
These are new options to be added.
list_sons: We need a command in the CLI Wallet similar to list_witnesses to get the list of SONs.
list_active_sons: This command should provide a list of active SONs on the Peerplays blockchain.
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).
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
Following table shows user sidechain addresses mapping
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.
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
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.
The functional requirement listed in this document will be limited to the multi-sig key change scenarios only.
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.
Various scenarios are outlined in the Scenarios section
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.
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.
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.
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
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.
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.
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.