本文介绍了 Helius 提供的 LaserStream 和 Sender 服务,它们共同构成了一个端到端的解决方案,旨在实现 Solana 上的零Slot执行。通过 LaserStream 快速检测链上事件信号,并利用 Sender 优化交易提交,确保交易能够以极低的延迟上链,从而抓住转瞬即逝的交易机会,为开发者提供更高效、可靠的交易工作流程。
每个人都希望他们的交易尽可能快地完成。然而,随着 Solana 交易基础设施变得越来越复杂,链上市场也日趋成熟,仅仅发送交易并祈祷一切顺利已经不够了——拥堵、竞争和网络怪癖将“快”变成了“令人沮丧的不可靠”。
目标很简单:当一个信号出现时——价格超过某个阈值、账户更新、程序被调用——对该信号做出反应的交易应该在同一个 slot 中完成。
这就是 零 slot 执行 的本质,其中检测和提交过程非常无缝,以至于在机会消失的几毫秒内就能抓住它们。
在实践中,这越来越难以实现,需要超低延迟的信号接收和可靠、确定性的交付。
Helius 同时提供这两者。
通过将用于闪电般快速事件检测的 LaserStream 与用于优化交易提交的 Sender 相结合,Helius 提供了一个端到端的 pipeline,专为零 slot 执行而构建。没有拼凑的基础设施,没有盲目的猜测,没有浪费的周期——只有最快的信号和通往 leaders 的最快路径,旨在为你的交易运营提供竞争优势。
Sender 通过几乎立即完成我的交易(大多数在一个 slot 内)始终优于其他服务。以前,由于更高的 slot 延迟,有利可图的交易经常流失,但现在 inclusion 几乎得到保证,并且更加可靠。Helius 始终提供出色的服务,而 Sender 是另一个突出的服务,直接提升了我的成功。
Alan
交易员
Sender 补充了 LaserStream,在 Solana 上创建了一个无缝的端到端 pipeline,用于响应式交易工作流程。在实践中,
借助 Helius,开发人员可以获得一个垂直集成的堆栈,专为速度和可靠性而构建:
Helius 已经通过 LaserStream 提供了同类最佳的信号检测,那么为什么不将其与 Sender 提供的同类最佳的交易发送相结合呢?
它们共同构成了一个用于 Solana 工作流程的单一、统一的 pipeline,其中每一毫秒都很重要。让 Helius 处理读写循环,以实现确定性的盈利结果。
那么,这在实践中是什么样的呢?
在 Solana 上,套利和清算可能在几毫秒内消失。及时检测到正确的链上信号至关重要。在这里,“信号”指的是任何实时事件,例如 token 转移、账户更新或程序调用,这些事件都提供了可交易的机会。如果没有超低延迟的接收,优势会在被利用之前消失,因此可靠、高速的数据流至关重要。
LaserStream 是 Helius 的下一代 Solana 数据流服务,它结合了 shred 级别 接收的速度和全球分布式服务的可靠性和覆盖范围,而无需运行多个专用节点的成本或运营负担。
LaserStream 的高级过滤功能使开发人员能够专注于特定信号,例如交易类型、账户更新以及一般的 block 流。
集成是无缝的,因为它被设计为 Yellowstone gRPC 的直接替代品,并且支持 多个客户端,包括 Rust、Go 和 TypeScript。
但是,拥有同类最佳的数据流服务仅仅是成功的一半,因为信号所呈现的机会包含两个部分:
LaserStream 在事件检测方面提供了优势,从而能够更有效地进行反应式交易提交。但是,LaserStream 不是交易发送服务,而且不幸的是,在 Solana 上有效地完成交易并不像发送一个简单的 sendTransactionRPC 调用 那么简单。
交易 inclusion 是一个多变量优化问题,需要深入了解 Solana 架构的多个领域。到达时间、模拟成功率、账户锁定冲突、相关交易费用和优先级等因素相互作用,以确定给定交易何时在链上执行。
在信号检测和交易创建工作流程中未能考虑任何一个因素都可能产生有害影响,将竞争优势转化为错失的机会。
例如,即使交易者在竞争对手之前几毫秒检测到信号,但延迟到达或费用不足也可能导致交易在链上失败,从而导致 profitable 的机会变成收入损失。
有效地完成交易需要一个整体的工作流程,该工作流程最大限度地提高优先级,最大限度地减少延迟,并预测整个堆栈中任何潜在的故障情况。
为了今天有效地在 Solana 上完成交易,开发人员需要:
Staked Connections 利用 Solana 的 Stake-Weighted Quality of Service (SWQoS),优先考虑来自 staked validators 和 paired RPC 的流量,以获得更好的 leader 可达性和传播速度。开发人员应通过 staked connections 进行路由,以最大限度地减少传播失败,从而缩短到达时间并提高 inclusion 率,而无需仅仅依赖公共端点,公共端点可能会受到拥塞的影响。
Priority fees 有助于提高交易在 Banking Stage 的 leader 调度程序中的位置,在该调度程序中,prio-graph(即,依赖感知优先级队列)根据每个 CU 的费用对链上执行进行排序。应动态计算 Priority fees,以避免静态值,静态值会导致过度支付或支付不足,从而阻碍访问有争议的状态的 inclusion。
Compute Units (CU) 量化了交易的计算需求。超过请求的预算会触发执行失败,而过度请求会增加 priority 成本。除非另有说明,否则交易默认将请求 200,000 CU。可以通过预先模拟交易以估计其消耗量,并使用 Compute Budget Program 的 SetComputeUnitLimit 指令请求特定数量来优化交易的 CU。
Commitment levels 确定了获取的数据(如 blockhashes)的确认深度,这些数据必须是最新的,以避免过期并确保交易的有效性。对于 getLatestBlockhash 调用,使用 confirmed 级别将比使用 finalized 级别快得多。
Preflight Checks 在提交之前在 RPC 节点上模拟交易,验证签名、指令和执行,以便及早发现错误。但是,这可能会增加 100 毫秒以上的延迟。对于时间敏感的工作流程以及开发人员完全确定他们正在发送格式正确的交易的情况,开发人员应在 sendTransaction RPC 方法中将 skipPreflight 参数设置为 true。
请注意,强烈 建议在不跳过 Preflight Checks 的情况下进行原型设计,以确保交易格式正确并成功在链上完成。虽然可以提高速度,但跳过 Preflight Checks 意味着盲目飞行—交易可能会因各种原因而失败,并且在跳过这些检查的情况下,不会深入了解交易失败的原因。
sendTransaction 方法中的 maxRetries 参数可以在发生故障时启用 RPC 端的自动重发。这可能效率低下,例如,发送具有过期 blockhashes 的重复交易。开发人员应将 maxRetries 设置为 0 以重新获得控制权,并实施他们自己的客户端重试,这些重试使用指数退避、在重新广播时刷新 blockhashes 和费用,并监控 blockheight 以优雅地使尝试过期。
Jito tips 通过 MEV 拍卖启用链下 bundle,确保部分 block 的交易 inclusion 和排序。这非常适合需要 top-of-block 执行或多个交易原子性的交易者或套利者。这对于高价值、时间敏感或任何竞争有争议状态的交易都非常有利。但是,这些拍卖会增加延迟,这实际上会使交易完成时间比通过 staked connections 发送经过良好优化的交易更糟。开发人员需要将这些协议外拍卖与 staked connections 的可靠性相结合,以便尽快完成他们需要的任何类型的交易。
实施这些最佳实践会产生复合效应,从而显着降低失败率并提高登陆可靠性。但是,手动管理此过程,以及跟上最新的协议开发并调整工作流程以适应这些新开发,需要大量的工程努力,包括不断调整、基础设施更改和错误处理——这些精力的更好用途原本可以用在其他地方。
Sender 是 Helius 的超低延迟交易发送服务,它利用 SWQoS 和 Jito 的链下拍卖来实现 MEV 优化的 inclusion,同时结合地理路由来最大限度地减少传播延迟。
通过同时通过 staked connections 和 Jito 的拍卖行发送交易,Sender 提供了双重交易途径,提高了可靠性并缩短了执行时间,而不会消耗任何额外的 credits。
Sender 适用于所有计划,默认速率限制为 6 TPS,可以根据要求进行升级。它专为需要确定性结果的交易者、MEV 搜索者和高频应用程序而构建。Sender 是 LaserStream 的补充,可为零 slot 执行启用无缝的反应式工作流程。
Sender 处理交易的方式与常规交易处理相同——通过简单的 JSON-RPC POST 请求,其中交易被序列化为 base64 并提交到其端点之一。
Sender 具有一个全局 HTTPS 端点,该端点会自动路由到最近的地理区域,因此建议前端应用程序使用它来避免 CORS 问题。
Sender 还具有多个区域 HTTP 端点,以实现最佳的服务器到服务器延迟(例如,盐湖城、东京、法兰克福)。
重要的是,没有通过 API 密钥进行身份验证——它是准系统的,接收和提交交易之间没有中间服务,因此非常适合超低延迟用例。
要有效地使用 Sender,必须按如下方式准备交易:
通过 Sender 发送的所有交易_必须_同时包含 tip 和 Priority fees。
需要 tip 才能启用对 Jito 基础设施和基于拍卖的交易 inclusion 的访问。Priority fees 会向 leader(即负责处理交易的 validator)发出信号,表明愿意为 priority 处理付费。这起到了双重好处,因为 tip 允许访问 Jito 的拍卖基础设施,而 Priority fees 提高了交易的优先级,两者共同作用以最大限度地提高交易 inclusion。
我们建议使用 Jito 的 tip floor API动态获取 tip(例如,取第 75 个百分位数并添加一个小的缓冲区),并使用 Helius 的 Priority Fee API获取 Priority fees。
提交后,Sender 将通过 SWQoS 和 Jito 并行调度交易,从而最大限度地提高交易 inclusion,而无需任何额外成本。
我们还建议通过 ping /ping(即 https://sender.helius-rpc.com/ping) 来预热空闲期间(即 >1 分钟)的连接,以避免冷启动。我们还建议遵循 交易提交的最佳实践,以进一步确保最佳的交易 inclusion。
LaserStream 提供与使用 gRPC 相同的开发人员体验。只需更改端点和 API 密钥以指向 LaserStream,即可立即获得 LaserStream 提供的所有好处。
对于现有代码,迁移就像以下一样简单:
从 Yellowstone 迁移到 LaserStream
// 之前:使用标准 Yellowstone gRPC
const connection = new GeyserConnection(
"your-current-endpoint.com",
{ token: "your-current-token" }
);
// 之后:使用 LaserStream(只需更改端点和 token)
const connection = new GeyserConnection(
"https://laserstream-mainnet-ewr.helius-rpc.com", // 选择离你最近的区域
{ token: "your-helius-api-key" }
);
我们建议使用 LaserStream 的客户端之一来简化开发过程。例如,打开订阅就像以下一样简单:
一个简单的订阅
// 使用专用的 LaserStream SDK
import { subscribe, CommitmentLevel, LaserstreamConfig } from 'helius-laserstream';
const config = {
apiKey: "your-helius-api-key",
endpoint: "https://laserstream-mainnet-ewr.helius-rpc.com" // 选择离你最近的区域
};
// SDK 自动处理:
// - 连接管理
// - 使用退避重连
// - 断开连接后的历史重播
// - 订阅管理
await subscribe(config, subscriptionRequest, handleData, handleError);
Helius Sender 适用于所有用户,不会消耗任何额外的 credits——无需付费计划或特殊访问权限。
要开始使用,请先在 Helius Dashboard 上创建一个帐户。然后,导航到 API Keys 部分并复制提供的密钥。这是获取 blockhashes 和确认交易所必需的,因为 Sender 仅处理交易提交。
以下是使用 Sender 的一个简单的 SOL 转账。此示例包括所有必需的组件——tip、Priority fee 和跳过 Preflight Checks。
使用 Sender 的一个简单的 SOL 转账
import { pipe } from "@solana/kit";
import {
createSolanaRpc,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
lamports,
getBase64EncodedWireTransaction,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
(async () => {
const HELIUS_API_KEY = "your_api_key";
const PRIV_KEY_B58 = "your_private_key";
const RECIPIENT = "recipient_address";
const TIP_ACCOUNTS = [\
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",\
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",\
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",\
"5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",\
"2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",\
"2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",\
"wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",\
"3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",\
"4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",\
"4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"\
];
// 从 base58 私钥中加载签名者
const ownerSigner = await createKeyPairSignerFromBytes(bs58.decode(PRIV_KEY_B58));
// 初始化 RPC 并获取 blockhash
const rpc = createSolanaRpc(`https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
// 构建并签名交易
const tx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(ownerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: 1000 }), m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitPriceInstruction({ microLamports: 200_000 }), m),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: RECIPIENT,
amount: lamports(1_000_000n), // 0.001 SOL
}),
m
),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)],
amount: lamports(1_000_000n), // 0.001 SOL
}),
m
)
);
const signedTx = await signTransactionMessageWithSigners(tx);
const base64Tx = getBase64EncodedWireTransaction(signedTx);
// 通过 Sender 发送
const res = await fetch("https://sender.helius-rpc.com/fast", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now().toString(),
method: "sendTransaction",
params: [\
base64Tx,\
{ encoding: "base64", skipPreflight: true, maxRetries: 0 },\
],
}),
});
const { result: sig, error } = await res.json();
if (error) throw new Error(error.message);
console.log("Transaction sent: ", sig);
console.log(`Explorer: https://orb.helius.dev/tx/${sig}?cluster=mainnet`);
})();
使用我们的 Node.js SDK 可以无缝地通过 Sender 发送交易。sendTransactionWithSender
method 处理所有计算单元和费用计算,包括动态的 Jito tips:
使用 Node.js SDK 的一个简化的 Sender 示例
import { createHelius } from "helius-sdk";
import { address, createKeyPairSignerFromBytes, lamports } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import bs58 from "bs58";
(async () => {
const apiKey = ""; // 来自 Helius 仪表板
const helius = createHelius({ apiKey });
try {
const feePayerSigner = await createKeyPairSignerFromBytes(
bs58.decode(process.env.FEEPAYER_SECRET ?? "")
);
const toPubkey = address("your_to_address");
const transferIx = getTransferSolInstruction({
amount: lamports(1_000_000n), // 0.001 SOL
destination: toPubkey,
source: feePayerSigner,
});
const sig = await helius.tx.sendTransactionWithSender({
signers: [feePayerSigner],
instructions: [transferIx],
version: 0,
commitment: "confirmed",
minUnits: 1_000,
bufferPct: 0.1,
region: "US_EAST",
swqosOnly: true,
pollTimeoutMs: 60_000,
pollIntervalMs: 2_000,
});
console.log("Confirmed signature:", sig);
console.log(
`Explorer link: https://orb.helius.dev/tx/${sig}?cluster=mainnet`
);
} catch (error) {
console.error("Error:", error);
}
})();
也可以使用我们的 Rust SDK 通过 send_smart_transaction_with_sender() 方法来简化此过程。
Helius 的真正力量在于将 LaserStream 和 Sender 组合成一个工作流程。LaserStream 在可操作信号发生的那一刻就会浮出水面,而 Sender 则确保对这些信号做出反应的交易能够尽快完成。
模式很简单:
以下是一个最小的示例,展示了实践中的完整工作流程:
一个统一的 LaserStream 和 Sender 工作流程
import bs58 from "bs58";
import { subscribe, CommitmentLevel } from "helius-laserstream";
import {
pipe,
createSolanaRpc,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
getBase64EncodedWireTransaction,
createKeyPairSignerFromBytes,
lamports,
address,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
const HELIUS_API_KEY = "your_api_key";
const LASERSTREAM_ENDPOINT = "https://laserstream-mainnet-ewr.helius-rpc.com"; // 选择最近的区域
const PRIV_KEY_B58 = "your_private_key";
const RECIPIENT = "recipient_address";
const TIP_ACCOUNTS = [\
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",\
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",\
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",\
"5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",\
"2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",\
"2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",\
"wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",\
"3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",\
"4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",\
"4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"\
];
// 示例:将流的范围限定为你关心的程序
const PROGRAM_OWNER_TO_WATCH = "11111111111111111111111111111111";
(async () => {
// 设置签名者并获取 blockhash
const ownerSigner = await createKeyPairSignerFromBytes(bs58.decode(PRIV_KEY_B58));
const rpc = createSolanaRpc(`https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`);
// 设置 LaserStream 配置和请求
const config = {
apiKey: HELIUS_API_KEY,
endpoint: LASERSTREAM_ENDPOINT,
};
// 为了减少噪音,我们将其范围限定为给定的程序
const request = {
accounts: {
watch: {
account: [],
owner: [PROGRAM_OWNER_TO_WATCH],
filters: [],
},
},
commitment: CommitmentLevel.PROCESSED, // 也可以更改为 CONFIRMED 以提高可靠性
slots: {},
transactions: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
};
// 在信号上,构建并通过 Sender 发送一个反应式交易
const handleData = async () => {
// 用于生存期的新鲜 blockhash
const { value: blockhash } = await rpc.getLatestBlockhash().send();
// 首先使用计算预算 ix 构建交易,然后使用用户 ix
const tx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(ownerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: 100_000 }), m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitPriceInstruction({ microLamports: 200_000 }), m),
(m) =>
// 在生产环境中,这可能是一个买入/卖出指令
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: address(RECIPIENT),
amount: lamports(1_000_000n), // 0.001 SOL
}),
m
),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: address(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]),
amount: lamports(1_000_000n), // 0.001 SOL tip
}),
m
)
);
const signedTx = await signTransactionMessageWithSigners(tx);
const base64Tx = getBase64EncodedWireTransaction(signedTx);
// 通过 Sender 发送(即,跳过 preflight 并且没有 RPC 端的重试)
const res = await fetch("https://sender.helius-rpc.com/fast", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now().toString(),
method: "sendTransaction",
params: [base64Tx, { encoding: "base64", skipPreflight: true, maxRetries: 0 }],
}),
});
const { result: sig, error } = await res.json();
if (error) throw new Error(error.message);
console.log("Reactive transaction sent: ", sig);
console.log(`Explorer: https://orb.helius.dev/tx/${sig}?cluster=mainnet`);
};
const handleError = console.error;
// 启动流(信号 → 反应式发送)
const stream = await subscribe(config, request, handleData, handleError);
console.log(`LaserStream subscription started (id: ${stream.id})`);
})();
Helius 是优化 Solana 上交易工作流程的首选,这归功于我们作为 网络上最大的 staked validator 的地位。因此,对于我们来说,staked bandwidth 不是问题,从而有效地消除了与拥塞期间交易优先级降低或数据包丢失相关的任何瓶颈或故障案例,从而为你的交易提供了直接的、高优先级的通往 leaders 的路径,没有任何限制。
通过将各种硬件和软件优化与我们的 staked bandwidth 深度集成,Helius 继续作为顶级提供商占据主导地位,拥有 最低的平均 slot 延迟——这证明了我们在 Solana 方面的垂直专业知识。
我们对 Solana 的承诺使我们处于最新研究和贡献的最前沿。例如,Chorus One 关于交易延迟的调查结果 表明,SWQoS 通常可以优于 Jito,从而缩短 inclusion 时间,特别是对于 p95 延迟大于 40 秒的用户。Sender 智能地通过 SWQoS 和 Jito 同时路由,从而确保所有交易类型的最大可靠性。
最终,拥有大量的 stake 并通过 staked connections 路由交易是在缩短 inclusion 时间时要考虑的最重要因素。
LaserStream 减少了延迟和不确定性。信号到达得越早,结果就越可预测。结合 Sender,发送交易以响应信号可以提高运营信心、更明智的决策以及更高的可靠性。这个 unified pipeline 不仅仅是孤立地优化速度——它优化了信心。
借助 LaserStream,开发人员知道他们正在使用市场上最好的数据流服务。借助 Sender,他们可以确定他们的交易通过最快、最可靠的路径路由到 block leaders。
总之,这产生了一种复合效应:
访问 Helius Dashboard 并立即开始使用。
- 原文链接: helius.dev/blog/zero-slo...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!