Optimism的挑战期

news2024/11/23 6:28:00

1. 引言

前序博客:

  • Optimism的Fault proof

用户将资产从OP主网转移到以太坊主网时需要等待一周的时间。这段时间称为挑战期,有助于保护 OP 主网上存储的资产。
而OP测试网的挑战期仅为60秒,以简化开发过程。

在这里插入图片描述

2. OP与L1数据交互

在这里插入图片描述

L1(以太坊)上的合约,可通过“bridging”,与L2(OP主网)上合约,进行交互。

同一网络内的Solidity合约调用,类似为:

contract MyContract {
    function doTheThing(address myContractAddress, uint256 myFunctionParam) public {
        MyOtherContract(myContractAddress).doSomething(myFunctionParam);
    }
}

MyContract.doTheThing会触发调用MyOtherContract.doSomething。在底层,Solidity通过向MyOtherContract合约发送ABI encoded call来触发调用doSomething函数。为简化开发者体验,此处抽象掉了很多这种复杂性。也可手工encoding(以更底层callabi.encodeCall函数)来实现相同的功能,如:

contract MyContract {
    function doTheThing(address myContractAddress, uint256 myFunctionParam) public {
        myContractAddress.call(
            abi.encodeCall(
                MyOtherContract.doSomething,
                (
                    myFunctionParam
                )
            )
        );
    }
}

以上两种调用方式等价。由于Solidity的限制,OP Stack的bridging接口被设计为看起来像第二个代码片段(即采用更底层的表达方式)。

2.1 L1与L2之间的基础通讯

从高层来看,L1与L2之间的数据发送流程,与以太坊上2个合约间的发送流程类似。L1与L2的通讯,可通过一组特殊的名为“messenger”的合约来实现。L1和L2有各自的messenger合约,用于抽象掉一些更底层的通讯细节,非常像HTTP库抽象掉物理网络连接。

每个messenger合约都有sendMessage函数,来向另一层的合约发送一个消息:

function sendMessage(
    address _target, //所调用的目标层上的合约
    bytes memory _message, //所发送的内容
    uint32 _minGasLimit //在目标层执行内容的最小gas limit
) public;

其等价为:

address(_target).call{gas: _gasLimit}(_message);

从而可调用个不同网络上的合约。
这掩盖了许多技术细节,这些细节使整件事在幕后运作,但这应该足以让你开始。想从以太坊上的合约调用OP主网上的合约吗?非常简单:

// Pretend this is on L2
contract MyOptimisticContract {
    function doSomething(uint256 myFunctionParam) public {
        // ... some sort of code goes here
    }
}
 
// And pretend this is on L1
contract MyContract {
    function doTheThing(address myOptimisticContractAddress, uint256 myFunctionParam) public {
        messenger.sendMessage(
            myOptimisticContractAddress,
            abi.encodeCall(
                MyOptimisticContract.doSomething,
                (
                    myFunctionParam
                )
            ),
            1000000 // or use whatever gas limit you want
        )
    }
}

具体可查看OP主网和测试网上合约地址 中的L1CrossDomainMessenger合约 和 L2CrossDomainMessenger合约。

2.2 通讯速度

不同于同一链上的合约调用,以太坊和OP主网间的调用不是即时的。跨链交易的通讯速度取决于方向:

  • 1)对于由L1->L2的交易:交易由L1(以太坊)到L2(OP主网),需约1到3分钟。因Sequencer需等待(包含该L1->L2交易区块之后的)一定数量的L1区块,以避免烦人的reorg问题。
  • 2)对于由L2->L1的交易:交易由L2(OP主网)到L1(以太坊),需要约7天。原因在于L1上的bridge合约,需等待该L2状态to be proven to the L1 chain之后,才能relay该message。
    由L2->L1的交易,分为4个不同的步骤:
    • 2.1)Step 1:将“给L1发送message”的L2交易,发送给Sequencer。这与其它L2交易类似,仅需数秒就可由Sequencer确认。
    • 2.2)Step 2:包含该L2交易的L2区块被提交给L1。这通常用时20分钟。
    • 2.3)Step 3:向L1上的OptimismPortal合约 提交该交易的proof。可在上面Step 2完成之后的任意时间提交。
    /// @notice Proves a withdrawal transaction.
    /// @param _tx              Withdrawal transaction to finalize.
    /// @param _l2OutputIndex   L2 output index to prove against.
    /// @param _outputRootProof Inclusion proof of the L2ToL1MessagePasser contract's storage root.
    /// @param _withdrawalProof Inclusion proof of the withdrawal in L2ToL1MessagePasser contract.
    function proveWithdrawalTransaction(
        Types.WithdrawalTransaction memory _tx,
        uint256 _l2OutputIndex,
        Types.OutputRootProof calldata _outputRootProof,
        bytes[] calldata _withdrawalProof
    )
        external
        whenNotPaused
    {
        // Prevent users from creating a deposit transaction where this address is the message
        // sender on L2. Because this is checked here, we do not need to check again in
        // `finalizeWithdrawalTransaction`.
        require(_tx.target != address(this), "OptimismPortal: you cannot send messages to the portal contract");
    
        // Get the output root and load onto the stack to prevent multiple mloads. This will
        // revert if there is no output root for the given block number.
        bytes32 outputRoot = l2Oracle.getL2Output(_l2OutputIndex).outputRoot;
    
        // Verify that the output root can be generated with the elements in the proof.
        require(
            outputRoot == Hashing.hashOutputRootProof(_outputRootProof), "OptimismPortal: invalid output root proof"
        );
    
        // Load the ProvenWithdrawal into memory, using the withdrawal hash as a unique identifier.
        bytes32 withdrawalHash = Hashing.hashWithdrawal(_tx);
        ProvenWithdrawal memory provenWithdrawal = provenWithdrawals[withdrawalHash];
    
        // We generally want to prevent users from proving the same withdrawal multiple times
        // because each successive proof will update the timestamp. A malicious user can take
        // advantage of this to prevent other users from finalizing their withdrawal. However,
        // since withdrawals are proven before an output root is finalized, we need to allow users
        // to re-prove their withdrawal only in the case that the output root for their specified
        // output index has been updated.
        require(
            provenWithdrawal.timestamp == 0
                || l2Oracle.getL2Output(provenWithdrawal.l2OutputIndex).outputRoot != provenWithdrawal.outputRoot,
            "OptimismPortal: withdrawal hash has already been proven"
        );
    
        // Compute the storage slot of the withdrawal hash in the L2ToL1MessagePasser contract.
        // Refer to the Solidity documentation for more information on how storage layouts are
        // computed for mappings.
        bytes32 storageKey = keccak256(
            abi.encode(
                withdrawalHash,
                uint256(0) // The withdrawals mapping is at the first slot in the layout.
            )
        );
    
        // Verify that the hash of this withdrawal was stored in the L2toL1MessagePasser contract
        // on L2. If this is true, under the assumption that the SecureMerkleTrie does not have
        // bugs, then we know that this withdrawal was actually triggered on L2 and can therefore
        // be relayed on L1.
        require(
            SecureMerkleTrie.verifyInclusionProof(
                abi.encode(storageKey), hex"01", _withdrawalProof, _outputRootProof.messagePasserStorageRoot
            ),
            "OptimismPortal: invalid withdrawal inclusion proof"
        );
    
        // Designate the withdrawalHash as proven by storing the `outputRoot`, `timestamp`, and
        // `l2BlockNumber` in the `provenWithdrawals` mapping. A `withdrawalHash` can only be
        // proven once unless it is submitted again with a different outputRoot.
        provenWithdrawals[withdrawalHash] = ProvenWithdrawal({
            outputRoot: outputRoot,
            timestamp: uint128(block.timestamp),
            l2OutputIndex: uint128(_l2OutputIndex)
        });
    
        // Emit a `WithdrawalProven` event.
        emit WithdrawalProven(withdrawalHash, _tx.sender, _tx.target);
    }
    
    • 2.4)Step 4:仅当fault挑战期(当前OP主网为7天) 结束之后,该交易才在L1上固化。该等待期是OP Stack安全模型的核心,无法规避。

2.3 访问msg.sender

合约会频繁使用msg.sender来基于calling address做决定。如,许多合约使用Ownable模式来选择性地约束对特定函数的访问。因为消息本质上是通过messenger合约在L1和L2之间穿梭的,所以当你接收到其中一条消息时,你会看到的 msg.sender将是与你所在的层相对应的messenger合约。
为此,每个messenger合约内均有xDomainMessageSender函数:

	/// @notice Retrieves the address of the contract or wallet that initiated the currently
    ///         executing message on the other chain. Will throw an error if there is no message
    ///         currently being executed. Allows the recipient of a call to see who triggered it.
    /// @return Address of the sender of the currently executing message on the other chain.
    function xDomainMessageSender() external view returns (address) {
        require(
            xDomainMsgSender != Constants.DEFAULT_L2_SENDER, "CrossDomainMessenger: xDomainMessageSender is not set"
        );

        return xDomainMsgSender;
    }

若你的合约被其中一个messenger合约调用,则可使用该函数来看实际上究竟是谁在发送该消息。在L2上实现onlyOwner modifier示例为:

modifier onlyOwner() {
    require(
        msg.sender == address(messenger)
        && messenger.xDomainMessageSender() == owner
    );
    _;
}

2.4 L1与L2之间发送数据的手续费

对于L1->L2交易:

  • L1->L2交易的大部分开销,源自L1上合约的执行。当发送L1->L2交易时,实际是调用了L1上的L1CrossDomainMessenger合约,然后调用L1上的OptimismPortal合约。这些在L1上的执行,会花费gas。L1->L2交易的总开销,最终由以太坊上的gas费决定。
  • L1->L2交易,会触发L2上的合约执行。OptimismPortal合约,会为L2执行,代为收取费用——burn掉动态量的L1 gas,具体量取决于所请求L2的gas limit。当更多人发送L1->L2交易时,所收取的L1 gas费会增加。当更少发送L1->L2交易时,所收取的L1 gas费会减少。
    • 由于代收取的L2执行gas量是动态的,所burn的gas在各个区块会各不相同。为避免gas燃尽,应总是为L1->L2交易gas limit增加至少20%的buffer。

对于L2->L1方向:

  • 由L2->L1的每个消息,需要3笔交易:
    • 1)L2交易:发起L2->L1启动交易,其定价与OP主网上的任何其他交易相同。
    • 2)L1证明交易:证明该L2交易。只有在L1上提交了包括该L2交易在内的L2区块后,才能提交此L1证明交易。该交易是昂贵的,因为它包括验证L1上的Merkle trie包含证明。
    • 3)L1固化交易:用于固化该L2交易。仅在该L2交易超过7天挑战期之后,才能提交L1固化交易。
  • L2->L1发送单个消息的总开销,包括:1笔L2启动交易和2笔L1交易开销。L1 proof交易和L1固化交易,通常要比L2启动交易贵得多。

2.5 挑战期

由L2->L1的消息,至少需要7天才能relay。这即意味着由L2发送的任意消息,只能过了一周的挑战期之后,才能在L1上收到。称其为“挑战期”的原因在于,在该期间,交易可被a fault proof挑战。
Optimistic Rollups是“乐观的”,因为其核心思想为:将某交易的结果发送到以太坊,而不在以太坊上实际执行该交易。在“乐观”情况下,该交易结果是正确的,可完全避免在以太坊上执行复杂(且昂贵)的逻辑。

但是,仍需要某种方式,来避免发布不正确的,而不是正确的,交易结果。为此,引入了“fault proof”。当某交易结果发布后,可将其看成“pending”一段时间,又名挑战期。在挑战期,任何人都可在以太坊上重新执行该交易,以试图证明所发布的结果是不正确的。

若某人证明该交易结果是错误的,则该结果将被删除,任何人都可以在该位置发布另一个结果(希望这次是正确的结果,经济惩罚会使错误的结果对发布者来说代价高昂)。一旦给定交易结果的窗口完全通过而没有受到质疑,则该结果可被视为完全有效(否则会有人对其提出质疑)。

无论如何,这里的重点是,在这个挑战期结束之前,不从L1上的智能合约内部对L1交易结果做出决定。否则,可能会根据无效的交易结果做出决策。结果,L2->L1 使用standard messenger合约发送的L1消息在等待整个挑战期之后才能被relay。

3. OP原理

为使L1gas开销最小化,OP Bedrock中的L2区块存储在以太坊链的非合约地址内:https://etherscan.io/address/0xff00000000000000000000000000000000000010。
这些L2区块作为交易calldata提交到以太坊,当该“交易”被包含在某具有足够attestations的区块内,则没法对其仅需修改或审查。从而OP主网可继承以太坊的可用性和完整性。

为降低开销,写入L1内的L2区块为压缩格式:
在这里插入图片描述
以压缩格式来在以太坊上存储L2区块,这很重要,因为写入到L1是OP主网交易的主要开销。

3.1 区块生成

Optimism区块生产主要由称为“Sequencer”的单一方管理,Sequencer主要提供如下服务:

  • 提供交易确认和状态更新。
  • 构建和执行 L2 区块。
  • 将用户交易提交到 L1。

在 Bedrock 中,Sequencer确实像以太坊那样有一个mempool,但该内存池是私有的,以避免为 MEV 提供机会。在 OP 主网中,区块每两秒生成一次,无论它们是空的(无交易)、被交易填充到区块 Gas limit、还是介于两者之间。

交易通过两种方式到达Sequencer:

  • 1)在 L1 上提交的交易(称为存款)包含在适当的 L2 链区块中。每个 L2 块都由“epoch”(它对应的 L1 块,通常发生在 L2 区块之前几分钟)及其在该epoch内的序列号来标识。该epoch的第一个区块包含其对应的 L1 区块中发生的所有存款。如果epoch试图忽略合法的 L1 交易,它最终会得到与Verifier不一致的状态,就像epoch试图通过其他方式伪造状态一样。这为 OP 主网提供了 L1 以太坊级别的抗审查能力。 可在协议规范Deriving the Transaction List中阅读有关此机制的更多信息。
  • 2)交易直接提交给Sequencer。这些交易的提交成本要低得多(因为不需要单独的 L1 交易费用),但它们当然不能抵抗审查,因为Sequencer是唯一了解它们的参与者。

目前,Optimism基金会在 OP 主网上运行唯一的区块生产者。有关未来计划对 Sequencer 角色进行去中心化。

在这里插入图片描述
基本工作流程为:

  • 1)用户将交易发送到主处理程序(Sequencer),然后主处理程序在其版本的第 2 层 (L2) 链上处理这些交易。
  • 2)处理后,Sequencer将交易详细信息和更新的第 2 层状态发送到第 1 层 (L1)。
  • 3)然后,其他第 2 层节点使用此交易更新其第 2 层链的版本。
  • 4)为了检查准确性,Verifier验证者节点将其更新状态与排序器提交的状态进行比较。

3.2 区块执行

op-geth组件所实现的执行引擎,使用两种机制接收区块:

  • 1)执行引擎可以使用对等网络与其他执行引擎进行自我更新。这与 L1 执行客户端通过网络同步状态的方式相同。具体见happy-path sync。
  • 2)op_node组件所实现的rollup节点从 L1 派生出 L2 区块。这种机制速度较慢,但​​具有抗审查性。具体见Worst-case sync。

3.3 在各层之间bridge ETH或token

Optimism 的设计目的是让用户可以在 L2(OP 主网、OP Sepolia 等)和底层 L1(以太坊主网、Sepolia 等)上的智能合约之间发送任意消息。这使得在两个网络之间传输 ETH 或代币(包括 ERC20 代币)成为可能。这种通信发生的确切机制根据消息发送的方向而有所不同。

OP 主网在标准桥中使用此功能,允许用户将代币从以太坊存入 OP 主网,也允许将代币从 OP 主网提取回以太坊。详情见Using the Standard Bridge。

  • 1)从以太坊迁移到 OP 主网:从以太坊(L1)到 OP 主网(L2)的交易称为存款。使用L1CrossDomainMessenger合约 或 L1StandardBridge合约,存款交易成为与存款所在的 L1 区块相对应的“epoch”的第一个 L2 区块中规范区块链的一部分。该 L2 块通常会在相应的 L1 块几分钟后创建。详情见Deposits。
  • 2)从 OP 主网迁移到以太坊:提款分为3个阶段:【详情见Withdrawals】
    • 2.1)通过 L2 交易初始化提款。
    • 2.2)等待下一个输出根提交到L1,然后使用 提交提款证明proveWithdrawalTransaction。这一新步骤可以对提款进行链下监控,从而更容易识别不正确的提款或输出根。这可保护 OP 主网用户免受一系列潜在的桥接漏洞的影响。
    • 2.3)故障挑战期结束后(主网一周,比测试网短),完成提现。

3.4 Fault proof 故障证明

在 Optimistic Rollup 中,状态承诺被发布到 L1(OP 主网的以太坊),没有任何直接证据证明这些承诺的有效性。相反,这些承诺被视为在一段时间内悬而未决(称为“挑战窗口”)。如果拟议的状态承诺在挑战窗口(当前设置为 7 天)期间没有受到挑战,则该承诺将被视为最终承诺。一旦承诺被认为是最终的,以太坊上的智能合约就可以安全地接受基于该承诺的有关 OP 主网状态的提款证明。

当状态承诺受到质疑时,可以通过“fault proof”过程使其无效。如果该承诺被成功质疑,那么它将被从承诺中删除,StateCommitmentChain(SCC)最终被另一个提议的承诺所取代。值得注意的是,成功的挑战不会回滚 OP 主网本身,只会回滚有关链状态的已发布承诺。交易的顺序和 OP 主网的状态不会因故障证明挑战而改变。

在这里插入图片描述

  • SCC:状态承诺链(SCC)合约包含提议的状态根列表,提议者断言这些状态根是规范交易链(CTC)中每笔交易的结果。这里的元素与CTC中的交易一一对应。
  • CTC:规范交易链(CTC)是必须应用于 OVM 状态的交易协议。
  • OVM:乐观虚拟机是一个符合第 2 层 (L2) 要求的执行框架,使汇总实现能够与以太坊的主区块链进行通信。
  • GETH:Geth 是以太坊区块链的执行客户端,用于处理交易。智能合约的部署和执行包括内置的 EVM。

作为 2021 年 11 月 11 日EVM 等效性的副作用,fault proof流程目前正在进行重大重新开发更新。

4. 为什么 Optimistic Rollup 挑战期为 7 天?

提款延迟是 Optimistic Rollup 的基本组成部分。当用户向以太坊提出有关 Optimistic Rollup 状态的声明时,就会开始提款。 如,这个声明可能是“我在 Optimism 上烧掉了 20 个代币,所以让我在以太坊上提取 20 个代币。”
由于 Optimistic Rollup 的重点在于 L1 并未实际执行 L2 链,因此 L1 不知道此声明是否有效。ZK Rollups 通过为 L1 提供一个加密证明来证明给定的声明是有效的,从而解决了这个问题。乐观汇总通过要求声明必须通过挑战期才能被视为有效来解决此问题。每个claim必须等待一段挑战期,在此期间挑战者可以声明该claim无效。如果有人对某个主张提出质疑,那么就会开始一些链上游戏来确定该主张是否真正有效。

由于某人检测无效声明并提交挑战可能需要一些时间,因此我们不可避免地需要挑战期大于零。毕竟,如果挑战期的持续时间是零秒,那么就没有机会提交挑战了。那么我们的问题就变成了:挑战期应该是多长?

最终状态的现代乐观汇总挑战游戏本质上采取提出主张的用户和质疑该主张的用户之间来回的形式(实际上,这些协议通常被设计为允许任何人参与要么是“团队”,但现在让我们保持简单)。为了举例,我们假设整个过程中有大约 10 个来回步骤(确切的数量有所不同,但在这里并不重要)。

如果双方都非常非常快,那么整个挑战过程至少需要 10 个以太坊区块(2 分钟)。当然,用户并不是像这样完全快,因此您可能需要添加一些至少是基线数字 10 倍的填充,即大约 100 个块(20 分钟)。尽管如此,100 个区块还是比进入 7 天挑战期的 50400 多个区块要短得多。这里一定还有别的东西。

攻击者可以用他们的钱做什么?攻击者的目标是阻止挑战者将他们的挑战交易包含在链上。毕竟,如果挑战交易成功,那么攻击就会失败。攻击者基本上有三种潜在的策略:

  • 1)对挑战者进行直接 DoS 攻击,首先阻止他们与 L1 网络交互
  • 2)通过昂贵的交易向 L1 网络发送垃圾邮件,以推高 Gas 价格并阻止挑战者进行交易
  • 3)通过控制大量验证者来直接审查挑战者

为什么挑战期是7天?

  • 因为它比保守的餐巾纸数学下限要长得多,也许更重要的是,它为整个以太坊社区留下了足够的时间陷入大规模困境。简而言之,利用 Optimistic Rollup 所需的攻击类型会在很长一段时间内显着降低以太坊上的交易体验。每个人都会非常生气。诚实的验证者会突然出现,愿意提交挑战交易以阻止攻击。一周给了我们足够的时间来协调社交层面的这种恢复。

更多详细内容,见:

  • Why is the Optimistic Rollup challenge period 7 days?

5. OP发展历程

OP发展历程为:

  • 2019年
    • 6 月,Plasma Group 开发人员创建了一个名为 Optimism Rollup 的可扩展性解决方案
  • 2020年
    • 2月,兼容EVM的乐观虚拟机(OVM)上线测试阶段
    • 9月,推出带有Optimism Rollup解决方案的测试网
  • 2021年
    • 一月份,Optimism 推出了 Alpha 版本
    • 10月,EVM主网升级启动
    • 8 月,以太坊和 Optimism 之间的成熟区块链桥梁启动。该桥此前只允许传输已启用的 ERC-20 代币
    • 12 月,加密世界庆祝 Optimism 主网发布
  • 2022年
    • 4月,宣布成立乐观集体(治理实验),并进行了多次空投。由于这一治理变化,乐观主义人民银行被解散,并创建了一个非营利组织——乐观主义基金会
    • 5 月,$OP 币开始分配

参考资料

[1] 2023年4月 为什么从 OP 主网转出资产需要等待一周?
[2] Sending Data Between L1 and L2
[3] L2IV RESEARCH 2024年1月29日 Why we invested in Rome Protocol? The Solana-Based Shared Sequencer
[4] Dispute Game
[5] Rollup Protocol Overview
[6] Withdrawal Flow
[7] Why is the Optimistic Rollup challenge period 7 days?
[8] 2023年10月博客 Ethereum’s Optimistic Future: An Introduction to Optimistic Rollups
[9] Optimism

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1422295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无人机除冰保障电网稳定运行

无人机除冰保障电网稳定运行 近日,受低温雨雪冰冻天气影响,福鼎市多条输配电线路出现不同程度覆冰。 为保障福鼎电网安全可靠运行,供电所员工运用无人机飞行技术,通过在无人机下方悬挂器具,将无人机飞到10千伏青坑线…

第5章 python深度学习——波斯美女

第5章 深度学习用于计算机视觉 本章包括以下内容: 理解卷积神经网络(convnet) 使用数据增强来降低过拟合 使用预训练的卷积神经网络进行特征提取 微调预训练的卷积神经网络 将卷积神经网络学到的内容及其如何做出分类决策可视化 本章将…

HBase表结构

HBase是非关系型数据库,是高可靠性、高性能、面向列、可伸缩、实时读写的分布式数据库。 HBase使用场景 大规模数据存储:如日志记录、数据库备份等。实时数据访问:如实时搜索、实时分析等。高性能读写:如高并发、低延迟的读写操…

(2)(2.10) LTM telemetry

文章目录 前言 1 协议概述 2 配置 3 带FPV视频发射器的使用示例 4 使用TCM3105的FSK调制解调器示例 前言 轻量级 TeleMetry 协议 (LTM) 是一种单向通信协议(从飞行器下行的数据链路),可让你以低带宽/低波特率(通常为 2400 波…

Linux下如何编译C/C++代码?从.c到.exe经历了什么?

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻强烈推荐优质专栏: 🍔🍟🌯C的世界(持续更新中) 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔…

百度智能小程序开发平台:SEO关键词推广优化 带完整的搭建教程

移动互联网的普及,小程序成为了众多企业和开发者关注的焦点。百度智能小程序开发平台为开发者提供了一站式的解决方案,帮助企业快速搭建并推广自己的小程序。本文将重点介绍百度智能小程序开发平台的SEO关键词推广优化功能,并带完整的搭建教程…

MySQL原理(三)锁定机制(1)综述

一、介绍: 1、锁的本质 业务场景中存在共享资源,多个进程或线程需要竞争获取并处理共享资源,为了保证公平、可靠、结果正确等业务逻辑,要把并发执行的问题变为串行,串行时引入第三方锁当成谁有权限来操作共享资源的判…

06 单目初始化器 Initializer

文章目录 06 单目初始化器 Initializer6.1 成员变量/函数6.2 初始化函数 Initialize()6.3 计算基础矩阵 F \boldsymbol{F} F 和单应矩阵 H \boldsymbol{H} H6.3.1 RANSAC 算法6.3.2 八点法计算 F \boldsymbol{F} F 矩阵: ComputeF21()6.3.3 计算基础矩阵 F \boldsymbol{F} …

基于yolov2深度学习网络的视频手部检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 输入mp4格式的视频文件进行测试,视频格式为1080p30. 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..........................…

大数据分析案例-基于随机森林算法构建电影票房预测模型

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

软连接和硬链接

1.软连接 软连接是一个独立的文件,有独立的inode,也有独立的数据块,它的数据块里面保存的是指向的文件路径-------相当于windows的快捷方式 删除一个软连接 2.硬链接 所谓的建立硬链接,本质就是在特定目录的数据块中新增文件名和…

【大数据】Flink SQL 语法篇(三):窗口聚合(TUMBLE、HOP、SESSION、CUMULATE)

Flink SQL 语法篇(三):窗口聚合 1.滚动窗口(TUMBLE)1.1 Group Window Aggregation 方案(支持 Batch / Streaming 任务)1.2 Windowing TVF 方案(1.13 只支持 Streaming 任务&#xff…

sqli-labs-master靶场训练笔记(1-22|新手村)

2024.1.21 level-1 (单引号装饰) 先根据提示建立一个get请求 在尝试使用单个单引号测试,成功发现语句未闭合报错 然后反手一个 order by 得到数据库共3列,-- 后面加字母防止浏览器吃掉 -- 操作(有些会&#xff09…

Java关于Excel文件的导入导出

人生如梦 荣华富贵 如木槿之花 朝荣夕逝 需求 导出: 能够将库表内的数据导出多个Excel表,并且生成一个压缩包,提供用户下载导入: 能够将一个压缩包内的多个Excel表解压,并获取表内的所有数据 FileUtils 工具类 publi…

GPT-SoVITS 本地搭建踩坑

GPT-SoVITS 本地搭建踩坑 前言搭建下载解压VSCode打开安装依赖包修改内容1.重新安装版本2.修改文件内容 运行总结 前言 传言GPT-SoVITS作为当前与BertVits2.3并列的TTS大模型,于是本地搭了一个,简单说一下坑。 搭建 下载 到GitHub点击此处下载 http…

【三维重建】运动恢复结构(SfM)

运动恢复结构是通过三维场景的多张图像,恢复出该场景的三维结构信息以及每张图片对应的摄像机参数。 欧式结构恢复(内参已知,外参未知) 欧式结构恢复问题: 已知:1、n个三维点在m张图像中的对应点的像素坐标 2、相机内参 求解&…

指针的深入了解6

1.回调函数 回调函数就是一个通过函数指针调用的函数。 如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数 时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用&#xff0…

字符串:getline、删除子串.erase()函数、插入子串.insert()函数

getline具体用法: 1、函数形式 getline ( cin,字符串类型:变量名);//默认以换行符结束 getline (cin, 字符串类型:变量名, ‘指定的结束符’); //指定换行结束符 2注意事项: 1)如果在使用getline()之前有使用scanf(…

Java基础--异常

异常 将程序执行中发生的不正常情况称为“异常”(语法错误和逻辑错误不是异常)。 异常时间分为两大类: 1.Error(错误):Java虚拟机无法解决的严重问题。Error 是严重错误,程序会崩溃。 2.Except…

【AI视野·今日NLP 自然语言处理论文速览 第七十七期】Mon, 15 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 15 Jan 2024 Totally 57 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Machine Translation Models are Zero-Shot Detectors of Translation Direction Authors Michelle Wastl, Ja…