目录

什么是支付通道?

注解

打开支付通道

进行支付

关闭状态通道

通道有效期

代码


什么是支付通道?

支付通道允许在无需发生交易的情况下多次转移以太。这意味着可以避免与交易相关的延迟和费用。 我们将探讨两方(Alice和Bob)之间的简单单向支付通道。 它涉及三个步骤:

  1. Alice 附加一些以太创建智能合约,可以称为“打开”了支付通道
  2. Alice会签署一些消息指明给接收者付款金额。 每次付款都会重复此步骤。
  3. Bob“关闭”支付通道,取回以太币,并将剩余部分发送回发送者。

注解

只有步骤1和3需要以太坊交易,步骤2意味着发送者通过离线方法(例如电子消息)将加密签名的消息发送给接收者。 这意味着只需要两个交易就可以支持任意数量(次数)的以太币转账。

Bob 保证会收到资金,因为智能合约托管以太并根据合法的签名消息来执行。 合约还可以强制超时执行,即使收款人拒绝关闭通道,Alice也能保证最终收回资金。 付款通道的参与者可以决定支付通道打开的持续时间。 对于短期交易,例如为网络访问的每一分钟支付一次网费,或者是长期的,例如向员工支付小时工资,支付可能持续数月或数年。

打开支付通道

要打开支付通道,Alice 需要部署智能合约,附加要托管的以太币并指定预期的收款人,以及通道存在有效时间。 合约的 SimplePaymentChannel 函数就是来做这个事情,代码在本节末尾。

进行支付

Alice 通过向 Bob 发送签名消息来付款。该步骤完全在以太坊网络之外执行。 消息由发送者以加密方式签名,然后直接传输给收款人。

每条消息都包含以下信息:

  • 智能合约的地址,用于防止交叉合约重放攻击。
  • 到目前为止所发送的以太总量。

在一系列转账结束时,付款通道仅需关闭一次。因此,只有一条消息被兑换。 这就是为什么每条消息都指定了以太的累计总量,而不是每次的微支付金额。 收款人自然而然的会选择兑换最新消息,因为这是以太总数最高的消息。 每条信息包含的nonce 将不再需要,因为智能合约仅执行一条信息。

包含合约地址用于防止一个支付通道的消息被用于不同的通道。

以下是修改后的JavaScript代码,用于对上一节中的消息进行加密签名:

function constructPaymentMessage(contractAddress, amount) {return abi.soliditySHA3(["address", "uint256"],[contractAddress, amount]);
}function signMessage(message, callback) {web3.eth.personal.sign("0x" + message.toString("hex"),web3.eth.defaultAccount,callback);
}// contractAddress is used to prevent cross-contract replay attacks.
// amount, in wei, specifies how much Ether should be sent.function signPayment(contractAddress, amount, callback) {var message = constructPaymentMessage(contractAddress, amount);signMessage(message, callback);
}

关闭状态通道

当Bob准备好收到他们的资金时,就可以通过调用智能合约上的 关闭 功能来关闭支付通道。 关闭通道会向接收方支付所欠的以太币并销毁合约,剩余的以太币返回Alice。为了关闭通道,Bob需要提供 Alice 签名过的消息。

智能合约必须验证信息是否包含发送者的有效签名。执行此验证的过程与上面收款人使用的方法相同。 Solidity函数 isValidSignature 和 recoverSigner 就是完成这个工作。

只有付款通道收款人可以调用 close 函数,其会选择最近的付款消息,因为该消息有最高的付款总额。 如果允许发送者调用此函数,他们可以提供较低金额的消息,来欺骗收款人。

函数会验证签名的消息是否与给定的参数匹配,如果匹配,收款人将收到应得的部分,余下的部分通过 selfdestruct 返还给发送者。 可以在完整的合约代码中看到 close 函数。

通道有效期

Bob可以随时关闭支付通道,但如果他没有这样做,Alice 需要一种方法来收回他们托管的资金。 一个方法是在合约部署时设置 到期时间 ,一旦达到那个时间,Alice 就可以调用 claimTimeout 收回他们的资金。 可以在完整的合约代码中查看 claimTimeout 函数。

调用此功能后,Bob无法再接收任何以太币,因此,Bob必须在到期前关闭频道。

代码

pragma solidity >=0.7.0 <0.9.0;contract SimplePaymentChannel {address payable public sender;      // 发送者address payable public recipient;   // 接收者uint256 public expiration;  // 到期时间constructor (address payable recipientAddress, uint256 duration)publicpayable{sender = payable(msg.sender);recipient = recipientAddress;expiration = block.timestamp + duration;}//判断是否是有效的签名function isValidSignature(uint256 amount, bytes memory signature)internalviewreturns (bool){bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));// 检查签名是否来自支付发送方 return recoverSigner(message, signature) == sender;}//关闭支付通道/// 接收方可以在任何时候关闭通道  /// 发送人指定签名金额, 接收人会收到这笔钱,  /// 剩下的将返回给发送者 function close(uint256 amount, bytes memory signature) external {require(msg.sender == recipient);//只有接收人可以关闭支付通道require(isValidSignature(amount, signature));//验证签名和金额recipient.transfer(amount);//接收人获得金额selfdestruct(sender);//合约自毁}/// 发送者可以在任何时候延长过期时间 function extend(uint256 newExpiration) external {require(msg.sender == sender);//只有发送者可以操作require(newExpiration > expiration);//新的时间要大于原来的时间才叫延长expiration = newExpiration;}/// 如果过期过期时间已到,而收款人没有关闭通道,可执行此函数,销毁合约并返还余额function claimTimeout() external {require(block.timestamp >= expiration);selfdestruct(sender);}//将被处理过的签名字段重新分割恢复原来的三部分function splitSignature(bytes memory sig)internalpurereturns (uint8 v, bytes32 r, bytes32 s){require(sig.length == 65);//内联汇编assembly {// first 32 bytes, after the length prefixr := mload(add(sig, 32))// second 32 bytess := mload(add(sig, 64))// final byte (first byte of the next 32 bytes)v := byte(0, mload(add(sig, 96)))}return (v, r, s);}//根据消息和签名恢复发送者的地址function recoverSigner(bytes32 message, bytes memory sig)internalpurereturns (address){(uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);return ecrecover(message, v, r, s);}/// duration构建一个带前缀的散列来模拟eth_sign的行为。function prefixed(bytes32 hash) internal pure returns (bytes32) {return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));}
}

Solidity:编写一个简单的支付通道相关推荐

  1. 【区块链】以太坊Solidity编写一个简单的Hello World合约

    熟悉一门语言得从Hello World! 开始,因为这是最简单的一个输出形式. 我们先在contracts目录下建立一个helloworld.sol文件 进入编辑 // SPDX-License-Id ...

  2. 用 Go 编写一个简单的 WebSocket 推送服务

    用 Go 编写一个简单的 WebSocket 推送服务 本文中代码可以在 github.com/alfred-zhon- 获取. 背景 最近拿到需求要在网页上展示报警信息.以往报警信息都是通过短信,微 ...

  3. 如何用FFmpeg编写一个简单播放器详细步骤介绍

    如何用FFmpeg编写一个简单播放器详细步骤介绍(转载) FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码.复用和解复用. ...

  4. 编写一个最简单的.php,学习猿地- 说明 如果我们要编写一个简单的PHP脚本,需要学习哪些...

    说明 如果我们要编写一个简单的 PHP 脚本,需要学习哪些基础知识呢? PHP 基础 PHP 脚本可放置于文档中的任何位置. 标准 的 PHP 脚本以 <?php 开头,以 ?> 结尾: ...

  5. java编写存钱_用Java编写一个简单的存款

    package desposit.money; public class DespositMoney { public static void main(String[] args) { Custom ...

  6. python脚本编写_如何用Python包编写一个简单的脚本,表达你对父母的爱?

    全文共2800字,预计学习时长6分钟 在繁忙的工作生活中,我们经常忘记给所爱的人发WhatsApp.本教程将使用Python包Twilio编写一个简单的Python脚本来发送WhatsApp消息.我们 ...

  7. 用java编写一个简单计算器

    java 采用java编写一个简单计算器,使用awt和swing 代码如下: import java.awt.Color; import java.awt.Font; import java.awt. ...

  8. ros如何编译python文件_Python为ROS编写一个简单的发布者和订阅者

    Python为ROS编写一个简单的发布者和订阅者 1.创建工作空间 1.1建立文件夹hello_rospy,再在该目录下建立子目录src,并创建工作空间 mkdir -p ~/hello_rospy/ ...

  9. Java制作一个盒子程序_编写一个简单的Java程序,模拟计算器的功能。

    提问:编写一个简单的Java程序,模拟计算器的功能. 网友回答: 程序参考: import java.awt.*; import java.awt.event.ActionEvent; import ...

最新文章

  1. OpenCV实现遍历文件夹下所有文件
  2. 卡巴斯基工业基础设施专用网络安全解决方案
  3. 计算机莫名其妙的游戏网页弹出,自动弹出游戏网页怎么办 自动弹出游戏网页解决方法【详解】...
  4. as本地仓库更改_Android Studio 之 Gradle与Project Structure详解
  5. 2021年回顾与展望
  6. vxworks中断的使用
  7. CTFshow php特性 web140
  8. win10安装ipython_windows10下安装IPython notebook 用来查看.ipynb文档
  9. Java FileInputStream close()方法与示例
  10. API文档工具-Swagger的集成
  11. Java面试必问!Spring事务扩展机制(2)
  12. python简明教程3.0_Python 简明教程 --- 0,前言
  13. 倒立摆及其应用//2021-2-23
  14. 禁止cmd dos 窗口被关闭
  15. 浅谈如何保障服务器安全
  16. OAEP及其在OpenSSL中的实现
  17. L1-039 古风排版 (20分)
  18. java 庖丁解牛api_重磅|庖丁解牛之——Flutter for Web
  19. 一眼就看懂;Android App 开发前景介绍及学习路线规划
  20. 星巴克利用地理位置应用发布咖啡速递手机应用

热门文章

  1. C4D+柔软建筑+人文关怀?听听SCI-Arc研究生怎么说
  2. Nginx---入门到放弃系列01
  3. 随着计算机科学技术和互联网,(题文)下列各句中加点成语的使用,全都正确的一项是、①随着计算机科学技术和互联网技术的快速......
  4. Linux命令 - mv命令
  5. c语言将元年1月1日起的天数转化成日期,不用循环和数组
  6. android+自定义桌面,Android桌面经典评测 Go桌面帮你自定义控制桌面
  7. 【纪念】微信公众号H5如何解决无法长按保存图片的问题
  8. python批量修改json文件
  9. 在Spring 中配置DBCP数据库连接池
  10. springboot添加多个properties或者yml配置文件