You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrypto测试:以Bucket为参数销毁代币时遇内核错误求助

解决Scrypto中burn_in_bucket函数的InvalidDropNodeVisibility错误

问题背景

我实现了一个供管理员销毁Bucket内代币的Scrypto函数burn_in_bucket,参考官方示例编写了交易清单(Manifest)及测试代码,但执行时出现KernelError(InvalidDropNodeVisibility)错误,怀疑deposit_batch调用存在问题,请求协助排查解决。

相关代码与信息

函数代码

pub fn burn_in_bucket(&mut self, mut bucket: Bucket) {
  assert!(bucket.resource_address() == self.token_vault.resource_address(), "input token invalid");
  let amount = bucket.amount();
  bucket.take(amount).burn();
}

测试代码及交易清单

let manifest = ManifestBuilder::new(&NetworkDefinition::simulator())
  .create_proof_from_account_by_amount(user.compo_addr, badge_amount, badge_addr)
  .withdraw_from_account_by_amount(user.compo_addr, amount, token_addr)
  .take_from_worktop_by_amount(amount, token_addr, |builder, bucket_id| {
      builder.call_method(component, func_name, args!(Bucket(bucket_id)))
  })
  .call_method(
      user.compo_addr,
      "deposit_batch",
      args!(Expression::entire_worktop()),
  )
  .build();
let receipt = test_runner.execute_manifest_ignoring_fee(
    manifest,
    vec![NonFungibleAddress::from_public_key(&user.public_key)],
);
receipt.expect_commit_success();

交易指令

Instructions:
├─ CALL_METHOD ComponentAddress("NormalComponent[0257...]") "lock_fee" Decimal("100");
├─ CALL_METHOD ComponentAddress("AccountComponent[03d8...]") "create_proof_by_amount" Decimal("3") ResourceAddress("NormalResource[00f1...]");
├─ CALL_METHOD ComponentAddress("AccountComponent[03d8...]") "withdraw_by_amount" Decimal("12") ResourceAddress("NormalResource[004a...]");
├─ TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("12") ResourceAddress("NormalResource[004a...]") Bucket("bucket1");
├─ CALL_METHOD ComponentAddress("NormalComponent[028f...]") "burn_in_bucket" Bucket("bucket1");
└─ CALL_METHOD ComponentAddress("AccountComponent[03d8...]") "deposit_batch" Expression("ENTIRE_WORKTOP");

错误信息

COMMITTED FAILURE: KernelError(InvalidDropNodeVisibility { mode: Application, actor: Method(
Scrypto { package_address: NormalPackage[0165...], blueprint_name: "StableCoin", ident: "burn_in_bucket" }, 
ResolvedReceiver { derefed_from: Some((Global(Component(NormalComponent[028f...])), 36)), receiver: Component([143, 123, 111, 139, 198, 156, 205, 139, 18, 0, 234, 91, 33, 85, 171, 28, 89, 180, 217, 77, 183, 128, 169, 59, 111, 177, 96, 148, 55, 190, 141, 232, 15, 4, 0, 0]) }), 
node_id: Bucket(1027) })

问题原因及解决方法

核心问题

InvalidDropNodeVisibility错误的本质是:burn_in_bucket函数接收了一个Bucket参数,执行过程中仅销毁了从Bucket取出的全部代币,但原Bucket(已为空)未被正确处理——既没有手动销毁,也没有返回给调用方,导致Scrypto内核无法处理这个残留的空Bucket节点。交易清单中的deposit_batch调用本身无问题,失败是由前面的函数逻辑错误导致。

修复步骤

  1. 简化函数逻辑(推荐)
    既然要销毁整个Bucket的代币,无需先take再burn,直接调用bucket.burn()即可,该方法会自动销毁Bucket:

    pub fn burn_in_bucket(&mut self, mut bucket: Bucket) {
      assert!(bucket.resource_address() == self.token_vault.resource_address(), "input token invalid");
      // 直接销毁整个Bucket的代币,Bucket会被自动回收
      bucket.burn();
    }
    
  2. 保留原逻辑时手动销毁空Bucket
    如果必须保留原有的take操作,需在函数末尾手动销毁空Bucket:

    pub fn burn_in_bucket(&mut self, mut bucket: Bucket) {
      assert!(bucket.resource_address() == self.token_vault.resource_address(), "input token invalid");
      let amount = bucket.amount();
      bucket.take(amount).burn();
      // 销毁空Bucket
      bucket.drop();
    }
    
  3. 验证交易逻辑
    原交易清单中的deposit_batch调用可以保留,它会确保工作台无残留资源,不会影响交易执行。

验证修复

重新运行测试代码,交易即可成功提交,不会再出现InvalidDropNodeVisibility错误。

内容的提问来源于stack exchange,提问作者Russo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:40:38