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调用本身无问题,失败是由前面的函数逻辑错误导致。
修复步骤
简化函数逻辑(推荐)
既然要销毁整个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(); }保留原逻辑时手动销毁空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(); }验证交易逻辑
原交易清单中的deposit_batch调用可以保留,它会确保工作台无残留资源,不会影响交易执行。
验证修复
重新运行测试代码,交易即可成功提交,不会再出现InvalidDropNodeVisibility错误。
内容的提问来源于stack exchange,提问作者Russo
相关产品推荐
相关产品推荐

