以太坊微支付通道原理与实现

线上直接转账需要一定的费用,如果存在大量小额交易的情况下,费用会变的难以承受,因而以太坊引入了微交易支付通道来解决这个问题。以太坊提供了一个票据支付方案,主要依赖于智能合约实现的一对多的账单系统。该账单系统大致上的执行流程如下.

  • 1:账单生成,同时提供机制往账单上存入保证金。

  • 2:交易发起人生成交易票据

  • 3:直接将票据发送给接收人

  • 4:接收人兑现票据,从合约转账(尽管某次兑现可能会失败,但是只要票据存在最终还是能够兑现).

这种交易优点在于可以在线下发送任意数量的交易,而只需要两个链上交易(存入保证金,兑现)只要存入保证金,线下通过交换票据进行任意数量的交易,避免了频繁的线上转账,节省了交易费用。

代码结构


  1. .
  2. ├── api.go //对外接口
  3. ├── cheque.go //账单
  4. ├── cheque_test.go
  5. ├── contract
  6. │   ├── chequebook.go //合约go语言接口
  7. │   ├── chequebook.sol //合约源码
  8. │   ├── code.go //合约byte码
  9. │   ├── mortal.sol //合约销毁
  10. │   └── owned.sol //hebe权限
  11. └── gencode.go //合约byte码生成

合约层

合约自身是接收转账的,用户可以在初始化或者后来增加金额,可以通过cash方法兑现票据,转账金额都会保存在send变量上。


  1. pragma solidity ^0.4.18;
  2. import "./mortal.sol";
  3. /// @title Chequebook for Ethereum micropayments
  4. /// @author Daniel A. Nagy <daniel@ethereum.org>
  5. contract chequebook is mortal {
  6. // Cumulative paid amount in wei to each beneficiary
  7. //已经支付的 可以控制双花,防止多次兑换票据
  8. mapping (address => uint256) public sent;
  9. /// @notice Overdraft event
  10. event Overdraft(address deadbeat);
  11. // Allow sending ether to the chequebook.
  12. function() public payable{ }
  13. /// @notice Cash cheque
  14. ///
  15. /// @param beneficiary beneficiary address
  16. /// @param amount cumulative amount in wei
  17. /// @param sig_v signature parameter v
  18. /// @param sig_r signature parameter r
  19. /// @param sig_s signature parameter s
  20. /// The digital signature is calculated on the concatenated triplet of contract address, beneficiary address and cumulative amount
  21. function cash(address beneficiary, uint256 amount, uint8 sig_v, bytes32 sig_r, bytes32 sig_s) public{
  22. // Check if the cheque is old.
  23. // Only cheques that are more recent than the last cashed one are considered.
  24. require(amount > sent[beneficiary]);
  25. // Check the digital signature of the cheque.
  26. bytes32 hash = keccak256(address(this), beneficiary, amount);
  27. require(owner == ecrecover(hash, sig_v, sig_r, sig_s));
  28. // Attempt sending the difference between the cumulative amount on the cheque
  29. // and the cumulative amount on the last cashed cheque to beneficiary.
  30. uint256 diff = amount - sent[beneficiary];
  31. if (diff <= this.balance) {
  32. // update the cumulative amount before sending
  33. sent[beneficiary] = amount;
  34. beneficiary.transfer(diff);
  35. } else {
  36. // Upon failure, punish owner for writing a bounced cheque.
  37. // owner.sendToDebtorsPrison();
  38. Overdraft(owner);
  39. // Compensate beneficiary.
  40. selfdestruct(beneficiary);
  41. }
  42. }
  43. }

支付层

账单保存了账本的位置,记账人,所有人等信

  1. // Chequebook can create and sign cheques from a single contract to multiple beneficiaries.
  2. // It is the outgoing payment handler for peer to peer micropayments.
  3. type Chequebook struct {
  4. path string // path to chequebook file
  5. prvKey *ecdsa.PrivateKey // private key to sign cheque with
  6. lock sync.Mutex //
  7. backend Backend // blockchain API
  8. quit chan bool // when closed causes autodeposit to stop
  9. owner common.Address // owner address (derived from pubkey)
  10. contract *contract.Chequebook // abigen binding
  11. session *contract.ChequebookSession // abigen binding with Tx Opts
  12. // persisted fields
  13. balance *big.Int // not synced with blockchain
  14. contractAddr common.Address // contract address
  15. sent map[common.Address]*big.Int //tallies for beneficiaries
  16. txhash string // tx hash of last deposit tx
  17. threshold *big.Int // threshold that triggers autodeposit if not nil
  18. buffer *big.Int // buffer to keep on top of balance for fork protection
  19. log log.Logger // contextual logger with the contract address embedded
  20. }

票据:合约位置,接收人,金额,签名


  1. type Cheque struct {
  2. Contract common.Address // address of chequebook, needed to avoid cross-contract submission
  3. Beneficiary common.Address
  4. Amount *big.Int // cumulative amount of all funds sent
  5. Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey)
  6. }

票据生成

生成一条支付记录,返回一份签名后的票据,收费这凭借这张票据从合约里面取钱.


  1. // Issue creates a cheque signed by the chequebook owner's private key. The
  2. // signer commits to a contract (one that they own), a beneficiary and amount.
  3. func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) {
  4. defer self.lock.Unlock()
  5. self.lock.Lock()
  6. if amount.Sign() <= 0 {
  7. return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
  8. }
  9. if self.balance.Cmp(amount) < 0 {
  10. err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance)
  11. } else {
  12. var sig []byte
  13. sent, found := self.sent[beneficiary]
  14. if !found {
  15. sent = new(big.Int)
  16. self.sent[beneficiary] = sent
  17. }
  18. sum := new(big.Int).Set(sent)
  19. sum.Add(sum, amount)
  20. sig, err = crypto.Sign(sigHash(self.contractAddr, beneficiary, sum), self.prvKey)
  21. if err == nil {
  22. ch = &Cheque{
  23. Contract: self.contractAddr,
  24. Beneficiary: beneficiary,
  25. Amount: sum,
  26. Sig: sig,
  27. }
  28. sent.Set(sum)
  29. self.balance.Sub(self.balance, amount) // subtract amount from balance
  30. }
  31. }
  32. // 账单余额少于阈值,自动补充.
  33. if self.threshold != nil {
  34. if self.balance.Cmp(self.threshold) < 0 {
  35. send := new(big.Int).Sub(self.buffer, self.balance)
  36. self.deposit(send)
  37. }
  38. }
  39. return
  40. }

存储金额


  1. func (self *Chequebook) Deposit(amount *big.Int) (string, error) {
  2. defer self.lock.Unlock()
  3. self.lock.Lock()
  4. return self.deposit(amount)
  5. }
  6. func (self *Chequebook) deposit(amount *big.Int) (string, error) {
  7. // since the amount is variable here, we do not use sessions
  8. depositTransactor := bind.NewKeyedTransactor(self.prvKey)
  9. depositTransactor.Value = amount
  10. chbookRaw := &contract.ChequebookRaw{Contract: self.contract}
  11. //转入金额
  12. tx, err := chbookRaw.Transfer(depositTransactor)
  13. if err != nil {
  14. self.log.Warn("Failed to fund chequebook", "amount", amount, "balance", self.balance, "target", self.buffer, "err", err)
  15. return "", err
  16. }
  17. // assume that transaction is actually successful, we add the amount to balance right away
  18. self.balance.Add(self.balance, amount)
  19. self.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", self.balance, "target", self.buffer)
  20. return tx.Hash().Hex(), nil
  21. }

兑换票据


  1. // Cash is a convenience method to cash any cheque.
  2. func (self *Chequebook) Cash(ch *Cheque) (txhash string, err error) {
  3. return ch.Cash(self.session)
  4. }
  5. // Cash cashes the cheque by sending an Ethereum transaction.
  6. func (self *Cheque) Cash(session *contract.ChequebookSession) (string, error) {
  7. v, r, s := sig2vrs(self.Sig)
  8. //调用合约的cash方法 提取代币
  9. tx, err := session.Cash(self.Beneficiary, self.Amount, v, r, s)
  10. if err != nil {
  11. return "", err
  12. }
  13. return tx.Hash().Hex(), nil
  14. }

其他接口

OutBox:用于在电对点网络中发行票据,提供了保证金存入,票据发行,自动存入保证金等接口。


  1. type Outbox struct {
  2. chequeBook *Chequebook
  3. beneficiary common.Address
  4. }
  5. // Issue creates cheque.
  6. func (self *Outbox) Issue(amount *big.Int) (swap.Promise, error) {
  7. return self.chequeBook.Issue(self.beneficiary, amount)
  8. }
  9. // AutoDeposit enables auto-deposits on the underlying chequebook.
  10. func (self *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
  11. self.chequeBook.AutoDeposit(interval, threshold, buffer)
  12. }

InBox:用于在电对点网络中票据兑换,提供了直接兑换,定时兑换,延迟兑换的接口功能。


  1. // Inbox can deposit, verify and cash cheques from a single contract to a single
  2. // beneficiary. It is the incoming payment handler for peer to peer micropayments.
  3. type Inbox struct {
  4. lock sync.Mutex
  5. contract common.Address // peer's chequebook contract
  6. beneficiary common.Address // local peer's receiving address
  7. sender common.Address // local peer's address to send cashing tx from
  8. signer *ecdsa.PublicKey // peer's public key
  9. txhash string // tx hash of last cashing tx
  10. session *contract.ChequebookSession // abi contract backend with tx opts
  11. quit chan bool // when closed causes autocash to stop
  12. maxUncashed *big.Int // threshold that triggers autocashing
  13. cashed *big.Int // cumulative amount cashed
  14. cheque *Cheque // last cheque, nil if none yet received
  15. log log.Logger // contextual logger with the contract address embedded
  16. }
  17. // Cash attempts to cash the current cheque.
  18. func (self *Inbox) Cash() (txhash string, err error) {
  19. if self.cheque != nil {
  20. txhash, err = self.cheque.Cash(self.session)
  21. self.log.Trace("Cashing in chequebook cheque", "amount", self.cheque.Amount, "beneficiary", self.beneficiary)
  22. self.cashed = self.cheque.Amount
  23. }
  24. return
  25. }

以太坊微支付通道原理与实现相关推荐

  1. 闪电网络RSMC协议技术原理----从微支付通道到RSMC(序列到期可撤销合约)

    闪电网络的RSMC协议技术原理 "if all tree falls in the forest and no one is around to hear it,does it make a ...

  2. 雷电网络 微支付通道

    1 微支付通道搭建: http://blog.hubwiz.com/2018/08/18/ethereum-payment-channel/   简易微支付通道搭建 https://ethfans.o ...

  3. 以太坊闪电网络实现原理

    2019独角兽企业重金招聘Python工程师标准>>> 以太坊闪电网络实现原理 线上直接转账需要一定的费用,如果存在大量小额交易的情况下,费用会变的难以承受,因而以太坊引入了微交易支 ...

  4. 从技术人视角看闪电网络之微支付通道

    (要看懂这篇文章,读者需掌握BTC基本原理,包括转账原理和多签地址.地址锁定时间.隔离见证) (感谢闪电网络很难懂?你需要看看这篇文章 | 硬核科普这个教程提供的图片) 比特币的价值传输相当安全,但是 ...

  5. 闪电网络预备知识二:微支付通道

    微支付通道 首先在介绍微支付之前,说说我对于区块链世界的理解.我们可以这样认为:首先区块链世界是去中心化的,也就是说没有一个中心机构.在现实世界中,中心机构可以作为一种权威,比如银行,你转账通过银行, ...

  6. 第13课 微支付通道(MicroPayment Channel) -- 迄今为止最透彻的讲解了

    有兴趣朋友也可以进一步关注公众号"架构之道与术", 获取原文. 或扫描如下二维码: 这1课很关键,微支付通道将是后面闪电网络.隔离见证的基础,微支付通道不能搞透彻,后面的闪电网络. ...

  7. 微支付通道与闪电网络

    参考链接: 闪电网络学习资源目录 一.微支付通道 微支付通道举例与理解 "如果森林里的一棵树倒了,而周围没有人听到,它会发出声音吗?" 应用场景: ​ 大量的小额交易,因为手续费的 ...

  8. 以太坊Bloom过滤器实现原理及应用场景分析

    一,Bloom过滤器的数据结构和reciept创建Bloom的过程 type Bloom [BloomByteLength]byte BloomByteLength = 256 Bloom 就是一个2 ...

  9. Ethereum 以太坊 交易数据 构建原理

    当我们需要将某些数据写入区块链,这个写入的过程叫交易.从区块链中取数据叫调用Call.交易有别与传统数据库数据的写入,以太坊区块链需要先将写入的数据编码成16进制的字节码,区块链块中存储的基础类型如: ...

最新文章

  1. 如何运用NLP向个性类型客户介绍产品
  2. [转载] Win7下MATLAB 7.0下载地址和详细安装
  3. jQuery EasyUI使用教程之创建标签页
  4. 开发者基础知识游戏,共10关,欢迎挑战
  5. python计算今年第几天_Python三种方法计算指定日期是今年的第几天
  6. LINUX之samba服务器的安装与配置(基于redhat 6.3发行版)
  7. 阿里巴巴发布第四财季财报 菜鸟驿站包裹量增长100%
  8. 16.Nginx 服务器的 gzip 压缩
  9. shell编程之函数简单使用
  10. ASP.NET文件的上传与下载
  11. Win7安装虚拟光驱蓝屏解决办法
  12. 视频教程-2020年软考网络规划设计师论文写作历年真题详解软考视频教程-软考
  13. 成绩造假!你看到400+大佬,有可能是P图!
  14. html5 pc端 客户端 web端的区别,wap版、手机版以及web的区别
  15. android carlife 源码,CarLife开发总结
  16. 雷神加速器无限更新失败️️️
  17. 微信营销系统(第三方微信平台)之微分销模块拓展
  18. 安装vs2015后C#注释变为英文
  19. 数据仓库DW、ODS、DM及其区别
  20. Makefile新手?千万别错过了《驾驭Makefile》

热门文章

  1. 人工智能与机器学习:两者有何不同?
  2. 贷后催收专用分案算法
  3. 播放器技术分享(2):缓冲区管理
  4. 如何判断笔记本蓝牙硬件坏了_怎么看笔记本蓝牙版本 不是蓝牙4.0?
  5. 百度地图API比例尺调整
  6. 解决Flutter Camera相机插件全屏幕画面拉伸问题
  7. 浅谈时尚杂志类APP开发
  8. 计算机视觉:图片缩放
  9. Odoo启动过程详解
  10. LVS DR模型及LVS持久连接