当前位置: 首页 > news >正文

剖析DeFi交易产品之UniswapV4:创建池子

本文首发于公众号:Keegan小钢


创建池子的底层函数是 PoolManager 合约的 initialize 函数,其代码实现并不复杂,如下所示:

function initialize(PoolKey memory key, uint160 sqrtPriceX96, bytes calldata hookData)externaloverrideonlyByLockerreturns (int24 tick)
{if (key.fee.isStaticFeeTooLarge()) revert FeeTooLarge();// see TickBitmap.sol for overflow conditions that can arise from tick spacing being too largeif (key.tickSpacing > MAX_TICK_SPACING) revert TickSpacingTooLarge();if (key.tickSpacing < MIN_TICK_SPACING) revert TickSpacingTooSmall();if (key.currency0 >= key.currency1) revert CurrenciesOutOfOrderOrEqual();if (!key.hooks.isValidHookAddress(key.fee)) revert Hooks.HookAddressNotValid(address(key.hooks));if (key.hooks.shouldCallBeforeInitialize()) {if (key.hooks.beforeInitialize(msg.sender, key, sqrtPriceX96, hookData) != IHooks.beforeInitialize.selector){revert Hooks.InvalidHookResponse();}}PoolId id = key.toId();uint24 swapFee = key.fee.isDynamicFee() ? _fetchDynamicSwapFee(key) : key.fee.getStaticFee();tick = pools[id].initialize(sqrtPriceX96, _fetchProtocolFees(key), _fetchHookFees(key), swapFee);if (key.hooks.shouldCallAfterInitialize()) {if (key.hooks.afterInitialize(msg.sender, key, sqrtPriceX96, tick, hookData)!= IHooks.afterInitialize.selector) {revert Hooks.InvalidHookResponse();}}// On intitalize we emit the key's fee, which tells us all fee settings a pool can have: either a static swap fee or dynamic swap fee and if the hook has enabled swap or withdraw fees.emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks);
}

不过,里面有很多信息,我们需要一一拆解才能理解。

先来看入参,有三个:keysqrtPriceX96hookDatakey 指定了一个池子的唯一组成,sqrtPriceX96 是要初始化的根号价格,hookData 是需要传给 hooks 合约的初始化数据。

关于池子的唯一组成,前文我们已经讲过,PoolKey 包含了五个字段:

  • currency0:token0
  • currency1:token1
  • fee:费率
  • tickSpacing:tick 间隔
  • hooks:hooks 地址

currency0currency1 和以前版本的 token0token1 一样,是经过排序的,currency0 为数值较小的代币,currency1 则为数值较大的代币。tickSpacing 和 UniswapV3 的一样,就不再解释了。hooks 是自定义的地址,具体如何实现后面再细说。

fee 则和之前的版本不一样了。UniswapV3 的 fee 只指定了固定的交易费率,但 UniswapV4 的 fee 其实还包含了动态费用、hook 交易费用、hook 提现费用等标志。fee 总共 24 位(bit),前 4 位用来作为不同的标志位,具体解析在 FeeLibrary 里实现,以下是其代码实现:

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.20;library FeeLibrary {// 静态费率掩码uint24 public constant STATIC_FEE_MASK = 0x0FFFFF;// 支持动态费用的标志位uint24 public constant DYNAMIC_FEE_FLAG = 0x800000; // 1000// 支持hook交易费用的标志位uint24 public constant HOOK_SWAP_FEE_FLAG = 0x400000; // 0100// 支持hook提现费用的标志位uint24 public constant HOOK_WITHDRAW_FEE_FLAG = 0x200000; // 0010// 是否支持动态费用function isDynamicFee(uint24 self) internal pure returns (bool) {return self & DYNAMIC_FEE_FLAG != 0;}// 是否支持hook交易费用function hasHookSwapFee(uint24 self) internal pure returns (bool) {return self & HOOK_SWAP_FEE_FLAG != 0;}// 是否支持hook提现费用function hasHookWithdrawFee(uint24 self) internal pure returns (bool) {return self & HOOK_WITHDRAW_FEE_FLAG != 0;}// 静态费率是否超过最大值function isStaticFeeTooLarge(uint24 self) internal pure returns (bool) {return self & STATIC_FEE_MASK >= 1000000;}// 获取出静态手续费率function getStaticFee(uint24 self) internal pure returns (uint24) {return self & STATIC_FEE_MASK;}
}

静态费率最大值为 1000000,表示 100% 费用。那么要设置 0.3% 的费率的话那就是 3000,这个精度和 UniswapV3 是一致的。

那如果是要支持静态费率,就假设静态费率为 0.3%,同时又要支持 hook 交易费和提现费,则需要同时设置这两个标志位,那 fee 字段用 16 进制表示的值为 0xC01778。其二进制表示为:11000000000101110111000,前面两个 1 就是两个标志位,后面的 101110111000 其实就是十进制数 3000 的二进制数。

另外,UniswapV3 的费率只能在指定支持的几个费率中选择一个,而 UniswapV4 取消了这个限制,费率完全放开了,由池子的创建者自己去决定要设置多少费率。

回到 initialize 函数,函数声明里还有一个函数修饰器 onlyByLocker,这也是需要展开说明的一个地方。我们先来看这个函数修饰器的代码:

modifier onlyByLocker() {address locker = Lockers.getCurrentLocker();if (msg.sender != locker) revert LockedBy(locker);_;
}

它要求调用者需是当前的 locker。要成为 locker,需要调用 PoolManager 合约的 lock() 函数。以下是 lock() 函数的实现:

function lock(bytes calldata data) external override returns (bytes memory result) {//把调用者添加到locker队列里Lockers.push(msg.sender);//需在这个回调函数里完成所有事情,包括支付等操作result = ILockCallback(msg.sender).lockAcquired(data);if (Lockers.length() == 1) {//只有一个locker的情况下,做清理操作if (Lockers.nonzeroDeltaCount() != 0) revert CurrencyNotSettled();Lockers.clear();} else {//不止一个locker的情况下,移出顶部的lockerLockers.pop();}
}

其中,Lockers 是封装了锁定操作的库合约,push() 函数会把当前调用者添加到锁定者队列里,具体实现用到了 EIP-1153 所引入的 tstore 瞬态存储操作码。具体原理不在这里展开。

而下一步是调用了 msg.sender 的回调函数 lockAcquired(),这一步非常关键,透露出很多信息。首先,这说明了,调用者需是一个合约才行,而不能是一个 EOA 账户。然后,调用者需实现 ILockCallback 接口,该接口只定义了一个函数,就是 lockAcquired() 函数。最后,调用者合约需在 lockAcquired() 函数里实现所有事情,包括完成支付和各种不同的交易场景,其实也包括了调用 initialize 函数。

我的理解,lock() 函数调用者应该是一个路由合约,或不同功能模块用不同的合约实现,比如可以加一个工厂合约用于完成创建池子的操作,但目前 UniswapV4 还没看到关于路由合约或工厂合约的实现,所以具体逻辑不得而知。

总而言之,到了这里,我们就已经知道了,创建池子的调用者需是一个实现了 ILockCallback 接口的合约,先调用 lock() 函数成为 locker,再通过 lockAcquired() 回调函数调其 initialize 函数来完成初始化池子。

回到 initialize 函数的具体实现。前面是一些基本的校验,我们摘出来看一下:

// 静态费率不能超过最大值
if (key.fee.isStaticFeeTooLarge()) revert FeeTooLarge();
// tickSpacing需在限定的有效范围内
if (key.tickSpacing > MAX_TICK_SPACING) revert TickSpacingTooLarge();
if (key.tickSpacing < MIN_TICK_SPACING) revert TickSpacingTooSmall();
// currency0需小于currency1
if (key.currency0 >= key.currency1) revert CurrenciesOutOfOrderOrEqual();
// hooks地址需是符合条件的有效地址
if (!key.hooks.isValidHookAddress(key.fee)) revert Hooks.HookAddressNotValid(address(key.hooks));

接着,判断是否需要调用 beforeInitialize 的钩子函数,如下:

if (key.hooks.shouldCallBeforeInitialize()) {if (key.hooks.beforeInitialize(msg.sender, key, sqrtPriceX96, hookData) != IHooks.beforeInitialize.selector){revert Hooks.InvalidHookResponse();}
}

钩子函数需返回该函数的 selector

之后的三行代码实现初始化逻辑,代码如下:

// 把key转为id
PoolId id = key.toId();
// 读取出交易费率
uint24 swapFee = key.fee.isDynamicFee() ? _fetchDynamicSwapFee(key) : key.fee.getStaticFee();
// 执行实际的初始化操作
tick = pools[id].initialize(sqrtPriceX96, _fetchProtocolFees(key), _fetchHookFees(key), swapFee);

这里面有好几个跟费用相关的函数,有必要说明一下。

isDynamicFee() 就是前面所说的 FeeLibrary 库合约的函数,判断是否设置了支持动态费用的标志位。如果不支持,则通过 getStaticFee() 读取出静态费率;如果支持动态费用,则通过 _fetchDynamicSwapFee() 获取费率。 _fetchDynamicSwapFee() 函数是在抽象合约 Fees 里实现的,其实现非常简单,就两行代码,如下所示:

function _fetchDynamicSwapFee(PoolKey memory key) internal view returns (uint24 dynamicSwapFee) {dynamicSwapFee = IDynamicFeeManager(address(key.hooks)).getFee(msg.sender, key);if (dynamicSwapFee >= MAX_SWAP_FEE) revert FeeTooLarge();
}

可见,其实是调用了 hooks 合约的 getFee() 函数。即是说,要支持动态费用,则 hooks 合约需要实现 IDynamicFeeManager 接口的 getFee() 函数。

_fetchHookFees() 函数也类似,需要 hooks 合约实现 IHookFeeManager 接口的 getHookFees() 函数。不过 getHookFees() 的返回值里其实是由两个费用组合而成的,一个是交易费,一个是提现费。返回值是 24 位,前 12 位是交易费,后 12 位是提现费。

_fetchProtocolFees() 函数则是用于获取协议费,这就和 hooks 合约没有关系了,是由一个实现了 IProtocolFeeController 接口的合约进行管理的。只有合约 owner 可以设置这个合约地址。目前 UniswapV4 还没有提供关于该合约的实现,短期内应该也不会开启收取协议费。

最后,通过调用 pools[id].initialize() 函数完成内部的初始化工作。这里的关键就是 pools 状态变量,新建的池子状态最终其实也是存储在了 pools 里。它是一个 mapping 类型的变量,如下:

mapping(PoolId id => Pool.State) public pools;

其 value 存的是一个 Pool.State 对象,这是一个定义在 Pool 库合约里的结构体,具体包含了如下数据:

struct State {Slot0 slot0;uint256 feeGrowthGlobal0X128;uint256 feeGrowthGlobal1X128;uint128 liquidity;mapping(int24 => TickInfo) ticks;mapping(int16 => uint256) tickBitmap;mapping(bytes32 => Position.Info) positions;
}

如果和 UniswapV3 对比就会发现,其实就是将 UniswapV3Pool 里的大部分状态变量移到了 State 里。另外,slot0 的字段与 UniswapV3Pool 的有所不同,以下是其具体字段:

struct Slot0 {// the current priceuint160 sqrtPriceX96;// the current tickint24 tick;uint24 protocolFees;uint24 hookFees;// used for the swap fee, either static at initialize or dynamic via hookuint24 swapFee;
}

可看到,与 UniswapV3Pool 的 Slot0 相比,没有了预言机相关的状态数据。另外,关于费用的字段总共有三个:protocolFeeshookFeesswapFee

pools[id].initialize() 函数的实现是在 Pool 库合约里,其代码逻辑很简单,就是初始化了 slot0,代码如下:

function initialize(State storage self, uint160 sqrtPriceX96, uint24 protocolFees, uint24 hookFees, uint24 swapFee)internalreturns (int24 tick)
{//当前状态下的根号价格不为0,说明已经初始化过了if (self.slot0.sqrtPriceX96 != 0) revert PoolAlreadyInitialized();//根据根号价格算出ticktick = TickMath.getTickAtSqrtRatio(sqrtPriceX96);//初始化slot0self.slot0 = Slot0({sqrtPriceX96: sqrtPriceX96,tick: tick,protocolFees: protocolFees,hookFees: hookFees,swapFee: swapFee});
}

再回到 PoolManager 合约自身的 initialize() 函数,还剩下最后一段代码如下:

if (key.hooks.shouldCallAfterInitialize()) {if (key.hooks.afterInitialize(msg.sender, key, sqrtPriceX96, tick, hookData)!= IHooks.afterInitialize.selector) {revert Hooks.InvalidHookResponse();}
}
//发送事件
emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks);

完成了 PoolManager 自身的初始化逻辑之后,就是判断是否需要再调用 hooks 合约的 afterInitialize 钩子函数了。最后发送事件,整个创建池子的流程就完成了。

相关文章:

剖析DeFi交易产品之UniswapV4:创建池子

本文首发于公众号&#xff1a;Keegan小钢 创建池子的底层函数是 PoolManager 合约的 initialize 函数&#xff0c;其代码实现并不复杂&#xff0c;如下所示&#xff1a; function initialize(PoolKey memory key, uint160 sqrtPriceX96, bytes calldata hookData)externalover…...

速盾:cdn内容分发服务有哪些优势?

CDN&#xff08;Content Delivery Network&#xff09;是指内容分发网络&#xff0c;是一种将网络内容分发到全球各个地点的技术和架构。在现代互联网架构中&#xff0c;CDN已经变得非常重要。CDN通过将内容分发到靠近用户的服务器上&#xff0c;提供高速、高效的服务。下面是C…...

如何利用React和Python构建强大的网络爬虫应用

如何利用React和Python构建强大的网络爬虫应用 引言&#xff1a; 网络爬虫是一种自动化程序&#xff0c;用于通过互联网抓取网页数据。随着互联网的不断发展和数据的爆炸式增长&#xff0c;网络爬虫越来越受欢迎。本文将介绍如何利用React和Python这两种流行的技术&#xff0c…...

炎黄数智人:招商局集团推出AI数字员工“招小影”

引言 在全球数字化浪潮的推动下&#xff0c;招商局集团开启了一项具有里程碑意义的项目。招商局集团将引入AI数字员工“招小影”&#xff0c;这一举措不仅彰显了招商局集团在智能化转型方面的坚定决心&#xff0c;也为企业管理模式的创新注入了新的活力。 “招小影”是一款集成…...

【开发篇】明明配置跨域声明,为什么却仍可以发送HTTP请求

一、问题 在SpringBoot项目中&#xff0c;明确指定仅允许指定网站跨域访问&#xff1a; 为什么开发人员却仍旧可以通过HTTP工具调用接口&#xff1f; 二、为什么 在回答这个问题之前&#xff0c;我们首先要了解一下什么是CORS&#xff01; 1、什么是CORS CORS的全称为跨域资源…...

单片机中有FLASH为啥还需要EEROM?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 一是EEPROM操作简单&…...

Qt的源码目录集合(V5.12.12版本)

目录 1.QObject实现源码 2.qml中的ListModel实现源码 3.qml中的JS运行时的环境和数据类型源码 1.QObject实现源码 .\Qt\Qt5.12.12\5.12.12\Src\qtbase\src\corelib\kernel\qobject.h .\Qt\Qt5.12.12\5.12.12\Src\qtbase\src\corelib\kernel\qobject.cpp .\Qt\Qt5.12.12\5…...

记因hive配置文件参数运用不当导致 sqoop MySQL导入数据到hive 失败的案例

sqoop MySQL导入数据到hive报错 ERROR tool.ImportTool: Encountered IOException running import job: java.io.IOException: Hive exited with status 64 报错解释&#xff1a; 这个错误表明Sqoop在尝试导入数据到Hive时遇到了问题&#xff0c;导致Hive进程异常退出。状态码…...

自动化邮件通知:批处理脚本的通讯增强

自动化邮件通知&#xff1a;批处理脚本的通讯增强 引言 批处理脚本在自动化任务中扮演着重要角色&#xff0c;无论是在系统管理、数据处理还是日常任务调度中。然而&#xff0c;批处理脚本的自动化能力可以通过集成邮件通知功能得到显著增强。当脚本执行完毕或在执行过程中遇…...

236、二叉树的最近公共祖先

前提&#xff1a; 所有 Node.val 互不相同 。p ! qp 和 q 均存在于给定的二叉树中。 代码如下&#xff1a; class Solution { public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if (root q || root p || root NULL) return root;TreeN…...

WebStorm 2024 for Mac JavaScript前端开发工具

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff08;适合自己的M芯片版或Intel芯片版&#xff09;&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功3、打开访达&#xff0c;点击【文…...

【Redis7】零基础篇

1 课程概述 2 Redis入门概述 2.1 是什么 Redis是基于内存的KV键值对内存数据库 Redis&#xff1a;Remote Dictionary Server(远程字典服务)是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;是一个高性能的Key-Value数据库提供了丰富的数据结构&#xff0c…...

[ROS 系列学习教程] 建模与仿真 - 使用 ros_control 控制差速轮式机器人

ROS 系列学习教程(总目录) 本文目录 一、差速轮式机器人二、差速驱动机器人运动学模型三、对外接口3.1 输入接口3.2 输出接口 四、控制器参数五、配置控制器参数六、编写硬件抽象接口七、控制机器人移动八、源码 ros_control 提供了多种控制器&#xff0c;其中 diff_drive_cont…...

Ubuntu22.04使用Systemd设置ROS 2开机自启动遇到的问题

在查找网上的各种开机自启动资料配置好开机自启动后&#xff0c;使用ros2 topic list不能显示话题。 1、问题解决&#xff1a;用户问题与domenID问题2、ROS2开机自启动服务教程3、多个ROS2开机自启动服务教程 1、问题解决&#xff1a;用户问题与domenID问题 在root用户下能看到…...

AI安全研究滞后?清华专家团来支招

在21世纪的科技浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;无疑是最为耀眼的一抹亮色。随着技术的不断突破&#xff0c;AI正以前所未有的速度融入我们的日常生活&#xff0c;重塑着社会、经济乃至人类文明的面貌。然而&#xff0c;在这股汹涌澎湃的发展洪流中&#…...

12寸FAB 信息部内外工作职责的一些划分构思

FAB的信息部&#xff0c;也常被称为IT部门或信息化部门&#xff0c;承担着确保整个制造工厂的信息技术系统高效、安全运行的职责。以下是 一、FAB信息部的一些关键部门职责&#xff1a; 1. 战略规划&#xff1a;制定和实施信息技术战略&#xff0c;以支持FAB的长期业务目标和增…...

css做旋转星球可举一反三

<!DOCTYPE html> <html lang"en"><head> <meta charset"UTF-8" /> <title>旋转的星球</title> <style type"text/css">.box {/*position: relative;*/position: absolute;width: 139px;height: 139p…...

AcWing 1256:扩展二叉树

【题目来源】https://www.acwing.com/problem/content/1258/【题目描述】 由于先序、中序和后序序列中的任一个都不能唯一确定一棵二叉树&#xff0c;所以对二叉树做如下处理&#xff0c;将二叉树的空结点用 补齐&#xff0c;如图所示。 我们把这样处理后的二叉树称为原二叉树…...

三维家:SaaS的IT规模化降本之道|OceanBase 《DB大咖说》(十一)

OceanBase《DB大咖说》第 11 期&#xff0c;我们邀请到了三维家的技术总监庄建超&#xff0c;来分享他对数据库技术的理解&#xff0c;以及典型 SaaS 场景在数据库如何实现规模化降本的经验与体会。 庄建超&#xff0c;身为三维家的技术总监&#xff0c;独挑大梁&#xff0c;负…...

ai智能语音机器人是如何影响客户体验的?电销机器人部署

随着人工智能技术的进步&#xff0c;越来越多的企业在寻求如何将人工智能技术融合到现有的商业模式上&#xff0c;进而实现自动化、智能化。在通信行业大量使用智能语音机器人、聊天机器人、客服机器人时&#xff0c;它能和“客户体验”并驾齐驱吗&#xff0c;还是可以让客户体…...

vue3使用v-html实现文本关键词变色

首先看应用场景 这有一段文本内容&#xff0c;是项目的简介&#xff0c;想要实现将文本中的关键词进行变色处理 有如下关键词 实现思路 遍历文本内容&#xff0c;找到关键词&#xff0c;并使用某种方法更改其字体样式。经过搜寻资料决定采用v-html实现&#xff0c;但是v-h…...

C#面:举列 a=10,b=15,在不用第三方变量的前提下,把a,b的值互换

要在不使用第三方变量的前提下交换a和b的值&#xff0c;可以使用异或运算。异或运算的特性是&#xff0c;对于两个相同的数进行异或运算&#xff0c;结果为0&#xff1b;对于任意数与0进行异或运算&#xff0c;结果为该数本身。因此&#xff0c;可以通过多次异或运算来实现变量…...

编写动态库

1.创建库.c .h文件 2.编写Makefile文件 3.make之后形成.so文件 4.make output,形成mylib 5.把mylib拷贝到test里面 mv mylib /test 6.编译 gcc main.c -I mylib/include -L mylib/lib -lmymethod形成a.out 但是直接执行会出现以下问题 很显然没有找到动态库 7.解决加载找不…...

记一次阿里云服务器java应用无法响应且无法远程连接的问题排查

问题表现 java服务无响应&#xff0c;无法远程链接到服务器。 今天中午12点多&#xff0c;应用直接崩溃。后续进入到服务器&#xff0c;发现java进程都不在了&#xff0c; 排查过程 先安装atop工具 安装、配置并使用atop监控工具 等下次再出现时看相关时间点日志&#xff…...

雷池WAF+Modsecurity安装防护及系统加固

君衍. 一、雷池WAF1、什么是雷池2、什么是WAF3、雷池的功能4、WAF部署架构5、整体检测流程 二、雷池WAF环境依赖1、查看本地CPU架构2、Docker安装2.1 卸载旧版本2.2 安装yum-utils工具包2.3 设置镜像仓库2.4 安装docker2.5 启动docker并查看版本 3、Docker Compose安装3.1 卸载…...

【Python】已解决:SyntaxError: positional argument follows keyword argument

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;SyntaxError: positional argument follows keyword argument 一、分析问题背景 在Python编程中&#xff0c;当我们在调用函数时混合使用位置参数&#xff08;p…...

leetcode-20-回溯-切割、子集

一、[131]分割回文串 给定一个字符串 s&#xff0c;将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回 s 所有可能的分割方案。 示例: 输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ] 分析&…...

利用深度学习模型进行语音障碍自动评估

语音的产生涉及器官的复杂协调&#xff0c;因此&#xff0c;语音包含了有关身体各个方面的信息&#xff0c;从认知状态和心理状态到呼吸条件。近十年来&#xff0c;研究者致力于发现和利用语音生物标志物——即与特定疾病相关的语音特征&#xff0c;用于诊断。随着人工智能&…...

TP8 JS(html2canvas) 把DIV内容生成二维码并与背景图、文字组合生成分享海报

方法一&#xff1a;前端JS生成(推荐) 注意&#xff1a; 1.这个网页只能截图图片效果代码&#xff0c;其它任何html效果都不能有&#xff0c;不然截图就不准确 2.如果要生成的图片DIV内容中引用了第三个方的图片&#xff0c;就是不使用同一个域名下的图片&#xff0c;需要把后…...

计算机科学中的接口(Interface)介绍

计算机科学中的接口&#xff08;Interface&#xff09;介绍 计算机科学中&#xff0c;接口是一个广泛的概念&#xff0c;在不同上下文中有不同含义&#xff1a; 1.任何两电路或设备间的连接电路&#xff0c;用于连接CPU与内存、CPU与外设之间。这是一个重要的硬件层面的接口概…...

大创项目推荐 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基…...

黑芝麻科技A1000简介

文章目录 1. A1000 简介2. 感知能力评估3. 竞品对比4. 系统软件1. A1000 简介...

详解C语言分支与循环语句

分支语句 if elseswitch 循环语句 whilefordo while goto语句 文章目录 1.什么是语句2.分支语句&#xff08;选择结构&#xff09;2.1 if语句2.1.1 悬空else2.1.3 练习 2.2 switch语句2.2.1 在switch语句中的break2.2.2 default子句 3.循环语句3.1 while循环3.1.1 while语句中…...

Python商务数据分析知识专栏(五)——Python数据分析的应用③使用Pandas进行数据预处理

Python商务数据分析知识专栏&#xff08;五&#xff09;——Python数据分析的应用③使用Pandas进行数据预处理 使用Pandas进行数据预处理1.合并数据2.清洗数据3.标准化数据4.转换数据 使用Pandas进行数据预处理 1.合并数据 2.清洗数据 3.标准化数据 4.转换数据...

Nosql期末复习

mongodb基本常用命令&#xff08;只要掌握所有实验内容就没问题&#xff09; 上机必考&#xff0c;笔试试卷可能考&#xff1a; 1.1 数据库的操作 1.1.1 选择和创建数据库 &#xff08;1&#xff09;use dbname 如果数据库不存在则自动创建&#xff0c;例如&#xff0c;以下…...

Pytest+Allure+Yaml+PyMsql+Jenkins+Gitlab接口自动化(四)Jenkins配置

一、背景 Jenkins&#xff08;本地宿主机搭建&#xff09; 拉取GitLab(服务器)代码到在Jenkins工作空间本地运行并生成Allure测试报告 二、框架改动点 框架主运行程序需要先注释掉运行代码&#xff08;可不改&#xff0c;如果运行报allure找不到就直接注释掉&#xff09; …...

SQL面试题练习 —— 查询前2大和前2小用户并有序拼接

目录 1 题目2 建表语句3 题解 1 题目 有用户账户表&#xff0c;包含年份&#xff0c;用户id和值,请按照年份分组&#xff0c;取出值前两小和前两大对应的用户id&#xff0c;需要保持值最小和最大的用户id排首位。 样例数据 ------------------------- | year | user_id | v…...

Arthas常见使用姿势

文章目录 Arthas常见使用姿势官网基本命令通用参数解释表达式核心变量说明常用命令一些常用特殊案例举例其他技巧关于OGNLOGNL的常见使用OGNL的一些特殊用法与说明OGNL内置的虚拟属性OGNL的个人思考OGNL的杂碎&#xff0c;收集未做验证 Arthas常见使用姿势 官网 https://arth…...

Apache Kylin的入门学习

Apache Kylin的入门学习可以从以下几个方面进行&#xff1a; 1. 了解Kylin的基本概念 定义&#xff1a;Apache Kylin是一个开源的分布式分析引擎&#xff0c;它基于Hadoop和HBase构建&#xff0c;提供Hadoop/Spark之上的SQL查询接口及多维分析&#xff08;OLAP&#xff09;能…...

React@16.x(46)路由v5.x(11)源码(3)- 实现 Router

目录 1&#xff0c;Router 的结构2&#xff0c;实现2.1&#xff0c;react-router1&#xff0c;matchPath.js2&#xff0c;Router.js3&#xff0c;RouterContext.jsx4&#xff0c;index.jsx 2.2&#xff0c;react-router-domBrowserRouter.jsxindex.jsx 1&#xff0c;Router 的结…...

openGauss真的比PostgreSQL差了10年?

前不久写了MogDB针对PostgreSQL的兼容性文章&#xff0c;我在文中提到针对PostgreSQL而言&#xff0c;MogDB兼容性还是不错的&#xff0c;其中也给出了其中一个能源客户之前POC的迁移报告数据。 But很快我发现总有人回留言喷我&#xff0c;而且我发现每次喷的这帮人是根本不看文…...

【国产开源可视化引擎Meta2d.js】快速上手

提示 初始化引擎后&#xff0c;会生成一个 meta2d 全局对象&#xff0c;可直接使用。 调用meta2d前&#xff0c;需要确保meta2d所在的父容器element元素位置大小已经渲染完成。如果样式或css&#xff08;特别是css动画&#xff09;没有初始化完成&#xff0c;可能会报错&…...

c#与倍福Plc通信

bcdedit /set hypervisorlaunchtype off...

【OceanBase诊断调优】—— 如何通过trace_id找到对应的执行节点IP

1. 前言 OceanBase作为分布式数据库&#xff0c;查问题找对节点很关键。好在OceanBase执行的每一条SQL都能通过trace_id来关联起来&#xff0c;知道trace_id怎么知道是在哪个节点发起的呢&#xff0c;请看本文。 2. trace_id生成规则 ob内部trace_id的生成函数如下&#xff0…...

鸿蒙开发Ability Kit(程序访问控制):【使用粘贴控件】

使用粘贴控件 粘贴控件是一种特殊的系统安全控件&#xff0c;它允许应用在用户的授权下无提示地读取剪贴板数据。 在应用集成粘贴控件后&#xff0c;用户点击该控件&#xff0c;应用读取剪贴板数据时不会弹窗提示。可以用于任何应用需要读取剪贴板的场景&#xff0c;避免弹窗…...

PL/SQL入门到实践

一、什么是PL/SQL PL/SQL是Procedural Language/Structured Query Language的缩写。PL/SQL是一种过程化编程语言&#xff0c;运行于服务器端的编程语言。PL/SQL是对SQL语言的扩展。PL/SQL结合了SQL语句和过程性编程语言的特性&#xff0c;可以用于编写存储过程、触发器、函数等…...

双非本 985 硕,我马上要入职上海AI实验室大模型算法岗

暑期实习基本结束了&#xff0c;校招即将开启。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解惑答疑&…...

C盘清理和管理

本篇是C盘一些常用的管理方法&#xff0c;以及定期清理C盘的方法&#xff0c;大部分情况下都能避免C盘爆红。 C盘清理和管理 C盘存储管理查看存储情况清理存储存储感知清理临时文件清理不需要的 迁移存储 磁盘清理桌面存储管理应用存储管理浏览器微信 工具清理 C盘存储管理 查…...

晚上睡觉要不要关路由器?一语中的

前言 前几天小白去了一个朋友家&#xff0c;有朋友说&#xff1a;路由器不关机的话会影响睡眠吗&#xff1f; 这个影响睡眠嘛&#xff0c;确实是会的。毕竟一时冲浪一时爽&#xff0c;一直冲浪一直爽……刷剧刷抖音刷到根本停不下来&#xff0c;肯定影响睡眠。 所以晚上睡觉要…...

ardupilot开发 --- 坐标变换 篇

Good Morning, and in case I dont see you, good afternoon, good evening, and good night! 0. 一些概念1. 坐标系的旋转1.1 轴角法1.2 四元素1.3 基于欧拉角的旋转矩阵1.3.1 单轴旋转矩阵1.3.2 多轴旋转矩阵1.3.3 其他 2. 齐次变换矩阵3. visp实践 0. 一些概念 相关概念&am…...

LESS 中的变量有什么作用?如何声明和使用变量?

LESS 中的变量可以用来存储和重用值&#xff0c;可以节省代码和提高可维护性。它们可以存储任何类型的值&#xff0c;如颜色、尺寸、字符串等。 在 LESS 中&#xff0c;变量的声明使用 符号&#xff0c;后面跟着变量的名称和值。例如&#xff1a; primary-color: #FF0000; f…...

Mongodb地理信息数据查询

在MongoDB中&#xff0c;可以使用地理空间查询来查找特定的地理位置信息。以下是一个使用MongoDB的地理空间查询的例子&#xff0c;假设我们有一个名为places的集合&#xff0c;它包含有关地点的信息&#xff0c;并且每个文档都有一个location字段&#xff0c;该字段包含一个地…...

C++ windows下使用openvino部署yoloV8

目录 准备版本&#xff1a; 准备事项: 选择配置界面&#xff1a; 下载界面&#xff1a; ​编辑 添加VS配置&#xff1a; 准备代码&#xff1a; yolov8.h yolov8.cpp detect.cpp 如何找到并放置DLL&#xff1a; 准备版本&#xff1a; opencv 4.6.0 openvino 2024.0…...

Elasticsearch优化索引映射和设置

在Elasticsearch的世界中&#xff0c;优化索引的映射&#xff08;mapping&#xff09;和设置&#xff08;settings&#xff09;对于提高搜索性能、存储效率和系统稳定性至关重要。本文将带您深入了解如何针对Elasticsearch的索引进行优化&#xff0c;帮助您构建更高效、更可靠的…...

云数据中心运维新纪元:让Linux服务器如虎添翼

文章目录 一、Linux系统管理的高级技巧1. 性能调优与监控&#xff1a;2. 自动化与脚本编写&#xff1a;3. 文件系统与存储管理&#xff1a; 二、服务器配置优化的策略1. 硬件选型与配置&#xff1a;2. 网络配置与优化&#xff1a;3. 应用部署与调优&#xff1a; 三、安全策略的…...

python代码报错:ModuleNotFoundError: No module named ‘docx‘

报错内容 D:\Anaconda\anaconda\envs\megaparse\python.exe F:\pythonproject\MegaParse-main\test.py Traceback (most recent call last):File "F:\pythonproject\MegaParse-main\test.py", line 1, in <module>from megaparse.Converter import MegaParse…...

20.98万元起!长安福特蒙迪欧运动版上市

2024年6月7日长安长安福特蒙迪欧运动版上市,新车共推出2款车型,厂商指导价20.98万元、22.98万元。动力上,搭载2.0T大马力E混动系统。外观方面,新车整体采用福特全新设计语言,看上去更加的运动。前脸8边形黑化蜂眼式前格栅,显得十分的运动。两侧采用分体式大灯组,上部细长…...

十分火爆!储蓄式国债今日开售!

今年以来,国债深受投资者欢迎,无论是储蓄国债还是超长期特别国债的销售频频上演“日光”“秒空”的场景。今日,2024年第三期和第四期储蓄国债在银行渠道正式开售。券商中国记者今日一早获悉,国债在手机银行渠道的销售十分火爆。记者注意到,工商银行手机APP显示,2024年第三…...

滔搏与FanaticsChina宣布开启合作进程,发力大中华区体育IP市

记者从总部位于上海的中国最大运动零售运营商滔搏获悉,其与全球领先的授权体育用品数字化平台Fanatics开启合作,共同拓展Fanatics旗下特许体育IP在大中华区的商业化运营。Fanatics除了与众多风靡全球的体育IP有着深度的合作伙伴关系外,也拥有知名的运动品牌与零售品牌,其业…...

云原生架构内涵_3.主要架构模式

云原生架构有非常多的架构模式&#xff0c;这里列举一些对应用收益更大的主要架构模式&#xff0c;如服务化架构模式、Mesh化架构模式、Serverless模式、存储计算分离模式、分布式事务模式、可观测架构、事件驱动架构等。 1.服务化架构模式 服务化架构是云时代构建云原生应用的…...

算法——链表

一、重新排队——蓝桥杯3255 1.2题解 思路 对1-n的数字进行m次操作得到的结果&#xff08;每次移动的是x&#xff09; 代码 #include <iostream> using namespace std; int main() {// 请在此输入您的代码int n,m;cin>>n>>m;int i1;int a[m][3];for(i;i…...

探索Django 5: 从零开始,打造你的第一个Web应用

今天我们将一起探索 Django 5&#xff0c;一个备受开发者喜爱的 Python Web 框架。我们会了解 Django 5 的简介&#xff0c;新特性&#xff0c;如何安装 Django&#xff0c;以及用 Django 编写一个简单的 “Hello, World” 网站。最后&#xff0c;我会推荐一本与 Django 5 相关…...