处理事务时出现 VM 异常:还原

Posted

技术标签:

【中文标题】处理事务时出现 VM 异常:还原【英文标题】:VM Exception while processing transaction: revert 【发布时间】:2021-11-23 12:24:45 【问题描述】:

我有 2 个合同。一种是 ERC721 令牌 (NFTCollectables)。另一个是包含拍卖系统的市场 (NFTMarket)。 拍卖结束后只能由出价最高的人申领。 在进行拍卖时,调用NFTCollectables 合约的transfer 方法将NFT 从市场地址转移到出价最高者的地址。

我不完全理解为什么会出现异常,但它发生在 NFTCollectables 合约的 transfer 方法中/内部。奇怪的是,即使transfer 方法中的最后一行代码也被执行(通过在_transfer(msg.sender, to, nftId) 之后放置require(false, 'test') 进行测试)。但ctr.transfer(auction.highestBid.bidder, auction.nftId) 之后没有任何内容被执行(通过在其后放置require(false, 'test') 进行测试)。

会不会和gas限制有关?

感谢任何想法,谢谢!

NFT 市场
function claimAuction(uint auctionIndex) external 
    require(auctionIndex < auctions.length, "no auction");
    Auction memory auction = auctions[auctionIndex];
    require(block.timestamp <= auction.end, "auction still active");

    NFTCollectables ctr = NFTCollectables(nftCollectablesAddress);
    ctr.transfer(auction.highestBid.bidder, auction.nftId);

    // deleting auction from active auctions list
    for (uint i; i < activeAuctionIndexes.length; i++) 
      if (activeAuctionIndexes[i] == auctionIndex) 
        delete activeAuctionIndexes[i];
        break;
      
    

    emit AuctionEnd(auction.highestBid.bidder, auction.highestBid.price, auction.nftId);

NFTCollectables
function transfer(address payable to, uint nftId) external payable 
    require(_exists(nftId), "transfer of non existing token");
    require(_isApprovedOrOwner(msg.sender, nftId), "Sender not approved nor owner");
    _transfer(msg.sender, to, nftId);

【问题讨论】:

如果你确定“transfer”的最后一行都被执行了,这意味着你的配置有错误。 【参考方案1】:

如果您已将合约部署在公共网络上,如主网或测试网,请使用https://tenderly.co 或 EtherScan 调试恢复原因。

如果您正在使用单元测试运行合同,请继续修改合同,例如通过删除行来查看它何时开始失败。或者使用更好的智能合约开发框架,例如Brownie,它可以让您立即恢复。

【讨论】:

奇怪的是,当transfer 方法为空时,我仍然会收到回复事件...您知道这可能会做什么吗?关于布朗尼的想法;我明天测试一下 因为问题不包含可重复的例子,所以你的猜测和我的一样好。我建议自己学习如何调试此类问题,这样您就可以系统地确定还原原因,而无需进行猜测。【参考方案2】:

我们已经在我们的代码库上实现了一个功能,我可以与您分享。此函数用于将 nft 的所有权转让给赢得拍卖的人。

function transferNFTtoNewOwner(NFTItem memory t,address oldOwner, address newOwner) internal 
    require(newOwner != address(0), "New owner can't be address zero.");
    XXXX storage r = creatureList[t.tokenAddress][t.tokenId];
    IERC721 nft = IERC721(t.tokenAddress);
    nft.safeTransferFrom(oldOwner, newOwner, t.tokenId); 
    address currOwner = nft.ownerOf(t.tokenId);
    require(newOwner == currOwner, "Problem on nft transfer");
    r.owner = newOwner; 

主要区别在于我们从这里使用了安全转移。如果你的合约拥有 NFT,那么你可以调用 safeTransfer。之后我们用 require 语句检查了 nft 所有者。如果您输入此语句并将您的传输功能更改为 safetransfer 并且交易仍然恢复并且在 etherscan 上没有给出任何错误,那么您可以调查您的 nft 合约。

【讨论】:

以上是关于处理事务时出现 VM 异常:还原的主要内容,如果未能解决你的问题,请参考以下文章

有些交易有效,有些则无效。处理事务时出现 UnhandledPromiseRejectionWarning 和 VM 异常

mysql事务处理失效原因

Hibernate 和 Spring:尝试创建事务时出现异常

spring事务没回滚

运行弹簧批处理作业的多个实例时出现死锁

SQLException : 处理 2 个不同的表时出现死锁错误