Smartraiden Interpretation of Micropayments

ZhangHQ · · 1259 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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.

Payment Channel 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.


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:ZhangHQ

查看原文:Smartraiden Interpretation of Micropayments

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1259 次点击  
加入收藏 微博
上一篇:mysql
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传