...
Table of Contents | ||
---|---|---|
|
Motivation
The purpose of the protocol is to transfer value between independent shards.
...
The cross-shard value transfer protocol provides a way for each of the clients to move value from their own wallets to a parent shard or back.
Outstanding issues
- how to do weighted multi-signature
- notification on block finalization (check with Michael Birch (Unlicensed) & Former user (Deleted))
- Should we have a shard DAG in a future version?
- how to roll-back cross-shard transfers when something goes wrong during the transfer?
- how to mount an existing shard?
- How to unmount a shard without destroying it?
- Why not register all the wallets in a public WalletRegistry?
- Do we sign the "approved" contracts used for REV?
- How to avoid the situation when the validators move their stakes out of the child shard while still holding their validator status?
- How does interaction with PoS contract happens at bonding/unbonding
- how to update K in order to keep the K/N ratio the same as validators bond/unbond. Should we keep the ratio in the config and re-compute K each time?
Architecture
The shards are organised in a tree structure.
...
The parent shard validators are not involved in the child shards.
Components
Common data structures
KonsensusConfig
- genesis_hash
- validators : [ ValidatorConfig ]
- k : Int
ValidatorConfig
- ip_address
- public_key
- expected_bond : Int
K-of-N consensus
KonsensusFactory
Creates the Konsensus contract. This extra layer is needed because the create call has to be confirmed by all the validators.
KonsensusFactory API | ||
---|---|---|
create | KonsensusConfig→ KonsensusFactory | Instantiates the K-of-N contract given the public keys of the validators and a given K value |
createKonsensus | Signature → Konsensus | Creates the consensus after all the signatures are accumulated. The expected signature is the name of Konsensus process, signed with the caller's private key. The call returns only when all the required signatures are accumulated. |
KonsensusProxy
This is used to control messages sent to a name. The notation KonsensusProxy[X] used further means that, after a message with K signatures is received the call will be forwarded to X.
...
KonsensusProxy | ||
---|---|---|
send | Message → Signature → Unit | Accumulates K signatures on a message. After all the K messages are received the message is forwarded to the underlying address. The expected signature is the message signed with the callers' private key. |
KoNsensus
A smart contract running in the parent shard which supervises the consensus in the child shard by running a K-of-N algorithm.
...
Konsensus API | ||
---|---|---|
getConfig | Unit → KonsensusConfig | returns the configuration of the Konsensus contract |
getUpdater | Unit → KonsensusProxy[KonsensusUpdater] | Creates an updater for this Konsensus instance, wrapped in a KonsensusProxy that requires signatures equal to the number of public-keys |
makeProxy | Name → KonsensusProxy[_] | Creates a proxy on top of an existing name |
KonsensusUpdater
Processes that require k-of-n consensus are wrapped in a KonsensusProxy by calling makeProxy
KonsensusUpdater API | ||
---|---|---|
updateConfig | KonsensusConfig → Unit | Updates the Konsensus contract configuration with a new set of validators and a new K value. |
Child-validator management
ValidatorManager
Holds the stakes placed by the stakeholders.
...
ValidatorManager API | ||
---|---|---|
create | [ValidatorConfig] → (KonsensusProxy[ValidatorManager], [StakeAdder] ) | Given a list of public keys of the child shard validators and their expected deposits returns a ValidatorManager, wrapped in a KonsensusProxy and a list of StakeAdderS |
addValidator | PublicKey → StakeAdder | starts the operation of adding a new validator. The operation is finished when the new validator places his stake by calling StakeAdder.placeStake |
removeValidator | PublicKey → Unit | starts the operation of removing an existing stakeholder from the depository |
StakeAdder
This contract has the authority to place a new stake in the ValidatorManager. This has to be a separate capability and cannot be put in ValidatorManager because it doesn't have to be wrapped in the KonsensusProxy and placeStake has to be called independently by the new validator.
StakeAdder API | ||
---|---|---|
placeStake | Signature → Purse → Validator | used by child-shard validators to place their initial deposits. The expected signature is the purse name signed with a private key registered with the ValidatorManager during its creation. |
Validator
The owner of the Validator instance has the right to withdraw his stake from the Depository, to the child-shard purse containing his tokens and can make a withdraw request.
...
Validator API | ||
---|---|---|
withdraw | Unit → Purse | returns a purse with the deposit placed by the validator. This call completes after removeValidator is called in the stake storage |
getChildPurse | Unit → Name | returns the name of the purse residing in the child shard and holding the equivalent of the placed stake in child shard tokens |
Depository
The Depository (aka "Fort Knox") is a pair of public smart contracts running in a parent shard.
...
Depository.Withdrawer API | ||
---|---|---|
withdraw | Amount → Purse | destroys the content of the purse and returns the name of a new purse located in the parent shard, minus fees. The new purse is sprouted from the Depository and its value + fees is removed from the Depository. The returned name is a wallet registered in the parent shard |
The Mint
The Mint is a pair of public smart contracts running in a child shard.
...
Purse API | ||
---|---|---|
split | Amount → Purse | creates a new purse containing the given amount. This amount is subtracted from the current purse. Empty purses are destroyed |
Wallets
A wallet is an address identified by a public key.
...
Wallet API | ||
---|---|---|
create | (Purse,PublicKey) → Wallet | Creates a wallet given a purse with the initial value and a public key. The purse is destroyed and the returned wallet will contain the value of the Purse minus fees |
deposit | Purse → Unit | Deposits a purse into this wallet. The purse is destroyed |
withdraw | Amount → Purse | Withdraws an amount from this wallet. A new purse is returned. |
getValue | Unit → Amount | returns the value stored in the wallet |
Shard tree setup
Sprout
Sprouting is the process of creating a child shard with an empty value stored inside.
...
See each of these steps described in details below
K-of-N Konsensus setup
In the parent-shard the Konsensus contract is instantiated through the following steps in order to avoid a MITM attack by the validator who initiates the process:
...
In the child shard a Konsensus contract also has to be instantiated and registered under a public name. The Konsensus in the client-shard to control the access to the Mint contract.
Mint & Depository setup
The Mint and Depository contracts are created and their names registered in their respective shard.
Stake placement
Removing a stakeholder
TODO. Interaction with Pos needs to be clarified
Adding a stakeholder
TODO. Interaction with Pos needs to be clarified
Child-shard absorption
Absorbing is the process of destroying a child shard while transferring all its value in the parent shard.
...
Unregistered child-shard wallets are also lost in the absorption process.
Mount
Through mounting, an existing shard is attached as a child of another existing shard.
TODO. We need to clarify how the mounting affects the clients of the shard
Umount
Through unmounting, a shard is detached from a shard tree and continues to live independently
TODO. We need to clarify how the unmounting affects the clients of the shard and the grandchild shards.
Atomic cross-shard value transfer
Each client only trusts his shard and the parents of his shard.
...
- Alice moves it's tokens to the root shard, which is the least common ancestor in this situation
- Alice transfers to a new wallet created with Bob's public-key in root shard
- Bob transfers his amount to "/d" shard
Parent-to-child transfer
TODO: Add diagrams and explain the steps
...
```rholang //session id creation
contract newId(return) =
{ new id in {
return!(*id.toByteArray)
}
} ```
Child-to-parent transfer
TODO: Add diagrams and explain the steps
...
- User in parent invokes the `transfer` function of the mint args: (purse, public key, return channel); returns session id over return channel
- Block containing 1. finalized
- Child Validators send messages to parent k-of-n contract
- Depository splits out a purse with the right number of tokens and wraps it in a wallet with the right public key, placing the result at `rho:uuid:<session id>`
- Blocks containing 3., 4. are finalized
- Child validators see 5. and each deploys a message to the k-of-n mint contract
- Confirmation sent to user over same return channel as 1.
- Blocks containing 6., 7. finalized
Useful links
https://blockstream.com/sidechains.pdf
...