The Foreword
In today's highly developed Internet, many people have become accustomed to digital payment, as long as there is a network, can transfer money at any time; But there are still many cases where there is no Internet connection, such as remote areas, islands, basements and other places where network signals are hard to reach or when the phone is down. Some might say alipay micro letter even if there is no network can also show me your payment code, but this way is the premise of the other party (b) must have a network, we list some of the scenes in front of is trade both sides does not have a network connection, which requires some new technologies and solutions, SmartRaiden without net micropayments is well solved the problem, let's from the Angle of the design and implementation to see exactly what it is.
Introduction
Smartraiden is a standard compliant implementation of the Raiden Network protocol using Golang, which enforces small-amount off-chain transactions on the mobile platform, and is able to run without Internet connection. For users can have a in-depth understanding about Smartraiden and feel free using it, we offer an outline briefly introducing relative concepts and procedures. At the beginning, there is a review of the Raiden Network.Next, we introduce primary functions and characteristics of Smartraiden. Then, we will give a showcase of fund-transferring transaction in the Smartraiden. In further detail, we have API specification and standard.
Review Raiden Network
Raiden Network is an off-chain scalability solution enforcing erc-20 compliant token transferring on the Ethereal. It allows for secure token transactions among participants without any global consensus mechanism, which is implemented through pre-set on-chain deposits transferring with digital signature and lock hash. We still rely on several on-chain processes to open and close a payment channel within a pair of nodes, so that it is incredibly hard for every pair of nodes on the network to create channels. However, if there exists one channel (at least), connecting two nodes through other nodes in the network, then we have no need to create another individual channel for these two nodes. This network is named as the Raiden Network, with all the contracts as to route algorithms and interlock channel communications.
Smartraiden uses payment channel network technology with the same principles of raiden network, but smartraiden is special designed in order to better fit for mobile nodes.We called the payment channel network which includes mobile nodes as smartraiden network for distinguishing the traditional raiden network.
SmartRaiden Contract and Channel lifecycle
SmartRaiden contract includes :
- Netting Channel Library :
0xad5cb8fa8813f3106f3ab216176b6457ab08eb75
- Channel Manager Library :
0xdb3a4dbae2b761ed2751f867ce197c531911382a
- Registry Contract :
0x68e1b6ed7d2670e2211a585d68acfa8b60ccb828
- Discovery Contract :
0x1e3941d8c05fffa7466216480209240cc26ea577
Spectrum contract registry address = 0x41Df0be8c4e4917f9Fc5F6F5F32e03F226E2410B
Channel lifecycle
- Channel nonexistence
There are two cases for channel nonexistence : one is our channel never exists, the other is we have already settled our transaction, so that all the data of channel and participants have been removed. Under both cases, we can not verify transactions among nodes, except that we create channels for our transactions.
- Channel open
There is channel creation between a node and its directly connected counterpart, channel creation operator has the right to indicate addresses of tokens, counterpart, and the number of token to deposit, and time period for settlement. Once channel opens, whereby participants can make their transactions.
Contract code:
/// @notice function to open a payment channel.
/// @dev It can be invoked by anyone, any times. Any pair of distinct addresses can create a channel, but cannot create multiple channels within the pair.
/// @param participant1 An address for a channel participant
/// @param participant2 The address for another other channel participant, cannot be the same as participant1.
/// @param settle_timeout Waited time between channel close and channel settle.
function openChannel(address participant1, address participant2, uint64 settle_timeout)
settleTimeoutValid(settle_timeout)
public
{
bytes32 channel_identifier;
require(participant1 != 0x0);
require(participant2 != 0x0);
require(participant1 != participant2);
channel_identifier = getChannelIdentifier(participant1, participant2);
Channel storage channel = channels[channel_identifier];
// ensure that channel has not been created.
require(channel.state == 0);
// Store channel information
channel.settle_timeout = settle_timeout;
channel.open_block_number = uint64(block.number);
// Mark channel as opened
channel.state = 1;
emit ChannelOpened(channel_identifier, participant1, participant2, settle_timeout);
}
- Channel deposit
We have only one node made deposits, after payment channel opens, so that only this node can transfer his tokens to his counterpart. Then this node can send a message informing that there is a payment channel opened for transaction to the counterpart, after which the counterpart is also able to deposit its tokens.
Contract code:
/// @notice internal function to be invoked when depositing tokens into this channel.
/// @dev this function must be invoked when channel has opened yet.
/// @param participant channel creator
/// @param partner the counterpart corresponding to participant.
/// @param amount the amount of tokens deposited in this channel.
/// @param from another address that transfers tokens to this channel.
/// @param need_transfer a boolean value confirms whether this channel need another source of value.
function depositInternal(address participant, address partner, uint256 amount, address from, bool need_transfer)
internal
{
require(amount > 0);
uint256 total_deposit;
bytes32 channel_identifier;
channel_identifier = getChannelIdentifier(participant, partner);
Channel storage channel = channels[channel_identifier];
Participant storage participant_state = channel.participants[participant];
total_deposit = participant_state.deposit;
if (need_transfer) {
// Do the transfer
require(token.transferFrom(from, address(this), amount));
}
require(channel.state == 1);
// Update the participant's channel deposit
total_deposit += amount;
participant_state.deposit = total_deposit;
emit ChannelNewDeposit(channel_identifier, participant, total_deposit);
}
Generally, channel opening and deposit are put together to save a lot of gas:
/// @notice function to open channel and meanwhile make some deposits inside with certain threshold of settle_timeout.
/// @dev parameter settle_timeout has to meet certain threshold in which case this function is able to operate.
/// @param participant channel creator
/// @param partner the counterpart corresponding to participant.
/// @param settle_timeout time period for channel to settle.
/// @param amount the amount of tokens to be deposited into this channel.
/// @param from another third party address to deposit tokens if need_transfer is true.
/// @param need_transfer a boolean value to confirm whether this channel need any token from outside.
function openChannelWithDepositInternal(address participant, address partner, uint64 settle_timeout, uint256 amount, address from, bool need_transfer)
settleTimeoutValid(settle_timeout)
internal
{
bytes32 channel_identifier;
require(participant != 0x0);
require(partner != 0x0);
require(participant != partner);
require(amount > 0);
channel_identifier = getChannelIdentifier(participant, partner);
Channel storage channel = channels[channel_identifier];
Participant storage participant_state = channel.participants[participant];
// make sure that this channel has not been created.
require(channel.state == 0);
// Store channel information
channel.settle_timeout = settle_timeout;
channel.open_block_number = uint64(block.number);
// Mark channel as opened
channel.state = 1;
if (need_transfer) {
require(token.transferFrom(from, address(this), amount));
}
participant_state.deposit = amount;
emit ChannelOpenedAndDeposit(channel_identifier, participant, partner, settle_timeout, amount);
}
- Channel transfer
Once a node has connected to the payment channel network, by AET token, under which it has access to another 5 nodes. It is quite easy for this node to transfer its token to another directly-connected node, but if it wants to transfer to the intermediate nodes among them, they both need to construct channels to the intermediate nodes, and if tokens in these nodes is sufficient for this transaction, then transaction occurs.
Transfer code:
/// @notice function to withdraw tokens while channel state is open. Anyone can invoke it.
/// @dev Once a participant proposes to withdraw, which has the same effect as cooperative settle, that is, any transfer are forbidden.
/// @dev After withdraw completes, transfers are able to resume.
/// @param participant The address for a channel participant
/// @param partner The address for the counterparts of participate
/// @param participant_balance The token balance of participant
/// @param participant_withdraw The amount of tokens that participant needs to withdraw
/// @param participant_signature The signature of participant
/// @param partner_signature The signature of partner
function withDraw(
address participant,
address partner,
uint256 participant_balance,
uint256 participant_withdraw,
bytes participant_signature,
bytes partner_signature
)
public
{
uint256 total_deposit;
bytes32 channel_identifier;
uint64 open_block_number;
uint256 partner_balance;
channel_identifier = getChannelIdentifier(participant, partner);
Channel storage channel = channels[channel_identifier];
open_block_number = channel.open_block_number;
require(channel.state == 1);
require(participant == recoverAddressFromWithdrawProof(channel_identifier,
participant,
participant_balance,
participant_withdraw,
open_block_number,
participant_signature
));
require(partner == recoverAddressFromWithdrawProof(channel_identifier,
participant,
participant_balance,
participant_withdraw,
open_block_number,
partner_signature
));
Participant storage participant_state = channel.participants[participant];
Participant storage partner_state = channel.participants[partner];
//The sum of the provided deposit must be equal to the total available deposit
total_deposit = participant_state.deposit + partner_state.deposit;
partner_balance = total_deposit - participant_balance;
require(participant_withdraw > 0);
require(participant_withdraw <= participant_balance);
require(total_deposit >= participant_balance);
require(total_deposit >= partner_balance);
participant_balance -= participant_withdraw;
participant_state.deposit = participant_balance;
partner_state.deposit = partner_balance;
channel.open_block_number = uint64(block.number);
require(token.transfer(participant, participant_withdraw));
//channel's status right now
emit ChannelWithdraw(channel_identifier, participant, participant_balance, partner, partner_balance);
}
- Channel close
If any node wants to shut down a certain channel connected to it, he can invoke close function. After that, channel close operator and its counterpart need to submit their balance proofs during the settlement.
Contract code:
/// @notice function to close a payment channel with balance proof from his channel counterpart.
/// @dev It can be invoked merely when channel state is open, and only by channel participants and only once.
/// @param partner The address of channel partner.
/// @param transferred_amount The amount of tokens that partner has been transferred till now.
/// @param locksroot The set of incomplete transfers that have been hash locked in partner's balanceproof.
/// @param nonce The newest serial number for partner's transfer.
/// @param additional_hash A hash value for auxiliary usage.
/// @param signature Partner's signature.
function closeChannel(
address partner,
uint256 transferred_amount,
bytes32 locksroot,
uint64 nonce,
bytes32 additional_hash,
bytes signature
)
public
{
bytes32 channel_identifier;
address recovered_partner_address;
channel_identifier = getChannelIdentifier(msg.sender, partner);
Channel storage channel = channels[channel_identifier];
require(channel.state == 1);
// Mark the channel as closed and mark the closing participant
channel.state = 2;
// This is the block number at which the channel can be settled.
channel.settle_block_number = channel.settle_timeout + uint64(block.number);
// Nonce 0 means that the closer never received a transfer, therefore never received a
// balance proof, or he is intentionally not providing the latest transfer, in which case
// the closing party is going to lose the tokens that were transferred to him.
if (nonce > 0) {
Participant storage partner_state = channel.participants[partner];
recovered_partner_address = recoverAddressFromBalanceProof(
channel_identifier,
transferred_amount,
locksroot,
nonce,
channel.open_block_number,
additional_hash,
signature
);
require(partner == recovered_partner_address);
partner_state.balance_hash = calceBalanceHash(transferred_amount, locksroot);
partner_state.nonce = nonce;
}
emit ChannelClosed(channel_identifier, msg.sender, locksroot, transferred_amount);
}
- Channel settle
Once payment channel close is invoked, settle timeout starts to count. During this period, both nodes submit the most recent message. After timeout, channel finishes the settlement.
Contract code:
/// @notice function to update channel partner's balance proof.
/// @dev It can be invoked merely by channel participants with multiples times if in channel lifecycle.
/// @param partner The address whose balance proof is about to get updated.
/// @param transferred_amount The amount of tokens that has been transferred from partner.
/// @param locksroot The set of transfers that has been hash locked.
/// @param nonce The serial number of transfers that partner has sent out.
/// @param additional_hash The hash value used for auxiliary usage.
/// @param partner_signature The signature of channel partner.
function updateBalanceProof(
address partner,
uint256 transferred_amount,
bytes32 locksroot,
uint64 nonce,
bytes32 additional_hash,
bytes partner_signature
)
public
{
bytes32 channel_identifier;
channel_identifier = getChannelIdentifier(partner, msg.sender);
Channel storage channel = channels[channel_identifier];
Participant storage partner_state = channel.participants[partner];
require(channel.state == 2);
require(channel.settle_block_number >= block.number);
require(nonce > partner_state.nonce);
require(partner == recoverAddressFromBalanceProof(
channel_identifier,
transferred_amount,
locksroot,
nonce,
channel.open_block_number,
additional_hash,
partner_signature
));
partner_state.balance_hash = calceBalanceHash(transferred_amount, locksroot);
partner_state.nonce = nonce;
emit BalanceProofUpdated(channel_identifier, partner, locksroot, transferred_amount);
}
Primary Functionalities and Characteristics in SmartRaiden
The primary goal for SmartRaiden aims to construct a structure to enforce an off-chain scalability solution for SmartRaiden Network, which improves usability, compatibility, and security.
Conventional functions include queries, registrations, channel dependencies, and transfers in different scenarios, as detailed in rest_api.
Additional functions include :
- Multiplatform & Mobile Adaptability
SmartRaiden network will be available on multiple platforms and decentralized micropayment on smart mobile devices can be realized. SmartRaiden currently can work on Windows, Linux, Android, iOS etc. SmartRaiden builds its own messaging mechanism on XMPP, not P2P, and separate nodes and start-up processes, making sure that it is capable of running on multiple platform with correct operations.
- Nodes State Synchronization
To make transaction secure, SmartRaiden adopts state machine to the design of nodes, ensuring relevant operations are atomic. For instance, it must be consistent with information of received unlock record of data and information sending out in the ACK message, both or neither are successful, no medium state existed. In the process of transactions, if any faulty condition occurs, ensure transaction state of both parties are consistent, and after crash recovery, either transaction continues or transaction fails, without any token loss.
- Internet-free Payment
It is a special functionality added in the SmartRaiden. Via network construction functions in meshbox, SmartRaiden is able to enforce off-chain fund transferring without reliance on the Internet.
- Third-party Delegation
Third-party delegation service, also known as SmartRaiden Monitoring, mainly used to facilitate mobile devices to enforce UpdateTransferDelegate & WithDraw on the blockchain by third-party delegation when they’re offline. Third-party service interacts with three parts in the system of out service, App, SmartRaiden, and spectrum.
- Fixed-rate Charge
Similar to Lightning Network, we have an additional fixed-rate charge function in the process of transferring tokens. Incentivized by this charge, all the nodes on this route will retain channel balance to improve the efficiency and higher the rate of successful transactions.
Showcases of Transactions in SmartRaiden
Assume that we have one node using AET token connected to our channel network, in which case, this node connects to another 5 nodes, and easy to transfer tokens to direct nodes. If this channel network gets complicated, then we have our tokens transferred though several nodes, and the state of nodes of this channel will alter successively.
Before the tx :
After the tx:
In this diagram, the addresses of each node are
- node 1 :
0x69C5621db8093ee9a26cc2e253f929316E6E5b92
- node 2 :
0x31DdaC67e610c22d19E887fB1937BEE3079B56Cd
- node 3 :
0xf0f6E53d6bbB9Debf35Da6531eC9f1141cd549d5
- node 4 :
0x6B9E4D89EE3828e7a477eA9AA7B62810260e27E9
- node 5 :
0x088da4d932A716946B3542A10a7E84edc98F72d8
And our transaction process starts from node 1, ends at node 5. However, we have only one route to 5, in the diagram, namely 1 to 2 to 4 to 5. After transaction completes, the alteration of balance tokens in this channel is
node 1 to node 2 : 0xc4327c664D9c47230Be07436980Ea633cA3265e4
node 1 initial deposit : 200
node 2 initial deposit : 100
node 1 balance : 150
node 2 balance : 150
node 2 to node 3 : 0xd1102D7a78B6f92De1ed3C7a182788DA3a630DDA
node 2 initial deposit : 100
node 3 initial deposit : 100
node 2 balance : 100
node 3 balance : 100
node 2 to node 4 : 0xdF474bBc5802bFadc4A25cf46ad9a06589D5AF7D
node 2 initial deposit : 200
node 4 initial deposit : 100
node 2 balance : 150
node 4 balance : 150
node 4 to node 5 : 0xd5CF2248292e75531d314B118a0390132bc7a5F0
node 4 initial deposit : 100
node 5 initial deposit : 100
node 4 balance : 50
node 5 balance : 150
Conclusion
At here, you have finished your learning about all the concepts and functionality specifications about SmartRaiden. For further usage, please go through installation instruction and tutorials or SmartRaiden Specification.
有疑问加站长微信联系(非本文作者)