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

本地Chainlink节点请求无法触发fulfill函数问题求助

Chainlink本地节点任务执行故障排查:fulfill函数未触发

请求已正常发起,但fulfillReEncryption函数未被调用,导致获取的数据无法保存。相关现象:

  • 任务列表最后一步标记为suspended,再次执行代码后变为completed
  • 尝试将minIncomingConfirmations设为0,但始终被覆盖为1

已提供的代码与配置

智能合约代码片段

function reEncryptData(
    string memory reEncryptionKey,
    string memory _encryptedData
) public returns (bytes32) {
    Chainlink.Request memory request = buildOperatorRequest(
        jobId,
        this.fulfillReEncryption.selector
    );
    request.add("reEncryptionKey", reEncryptionKey);
    request.add("encryptedData", _encryptedData);
    return sendOperatorRequest(request, fee);
}

function fulfillReEncryption(
    bytes32 requestId,
    bytes memory _data
) public recordChainlinkFulfillment(requestId) {
    reEncryptedData = string(_data);
}

任务配置文件(.toml)

type = "directrequest"
schemaVersion = 1
name = "Re-Encrypt Data"
contractAddress = "0xC1CD77E8cd5FB78898815952117Aca334fe573cd"
maxTaskDuration = "0s"
minIncomingConfirmations = "0"
observationSource = """
    decode_log   [type=ethabidecodelog
                  abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)"
                  data="$(jobRun.logData)"
                  topics="$(jobRun.logTopics)"]

    decode_cbor  [type=cborparse data="$(decode_log.data)"]
    fetch        [type=bridge name="re-encrypt" requestData="{\"id\": $(jobSpec.externalJobID), \"data\": { \"encryptedData\": $(decode_cbor.encryptedData), \"reEncryptionKey\": $(decode_cbor.reEncryptionKey)}}"]
    parse        [type=jsonparse path="data,reEncryptedData" data="$(fetch)"]
    encode_large [type=ethabiencode abi="(bytes32 requestId, bytes _data)" data="{\"requestId\": $(decode_log.requestId), \"_data\": $(parse) }"]
    encode_tx    [type=ethabiencode
                  abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
                  data="{\"requestId\": $(decode_log.requestId), \"payment\": $(decode_log.payment), \"callbackAddr\": $(decode_log.callbackAddr), \"callbackFunctionId\": $(decode_log.callbackFunctionId), \"expiration\": $(decode_log.cancelExpiration), \"data\": $(encode_large)}"
                 ]
    submit_tx    [type=ethtx to="0xC1CD77E8cd5FB78898815952117Aca334fe573cd" data="$(encode_tx)"]

    decode_log -> decode_cbor -> fetch -> parse -> encode_large -> encode_tx -> submit_tx
"""

合约调用代码

await (
    await reEncryption
      .connect(dataSubject)
      .reEncryptData(
        "d48065aceb01496e1e4f8f74c7b68422ba16e1de7c80a9e927683f30c42b150804d505e4835912f719e96fd27f8e42345aa757070f5fa083974f5fb82fd384b4bdc74dbd75b6a60c68108d97e4c8dcd02c12a7d5552e28df3a7af366bb05b86ace",
        "eyJrZXkiOiIwNGU5MjcwMzhiMjFjMDJhZDI2MmUxZmMwNmY4YmU0NTFiYmUyODU0Y2FmZGNmMDg4YzY5NDBjNTUzMjI4M2E3OTE5NTY1NDU0N2ZjZmQ2Yzg1OWJiZWQ2NmNlZmNlN2FkOTUyMDhkNmI5MjNkNjVkYjRmNTQyYWEwYTI3M2VmY2U1MDRmMTE4NmRkYzMxMjZhYWMwNGJhZWNlN2I5NDA4YzkwMDVkY2Q2MjJhYTlkY2E4YjU4NDg1MmI0NjU0MzAyNzMwM2U4NjA2MWRlNTNmYjcxNzk1NTAzZjNiYzRiNDMyNTJhNWFiODRiZDE2YmZkN2M4ZjYzZWRmMWM1ODIzZjVlZDNlYzg3OGJmNGY0ZTAzMmYxN2NiNWI5Y2RlOWU1YzMwN2U5NzI4ZjJmYzBhMWUwNGM2NzA2MDRjM2MyM2Q1NWIiLCJjaXBoZXIiOiJlcGtLVU1abEU1Q29Ucm1RbUUydkFRPT0ifQ=="
      )
).wait();

已完成的前置配置:

  • 使用Operator.sol部署合约
  • 为目标合约和Operator合约充值LINK
  • 为Oracle节点账户充值ETH和LINK
  • 将Oracle节点地址添加至setAuthorizedSenders列表

排查步骤

1. 定位minIncomingConfirmations被覆盖的原因

  • Operator.sol默认minIncomingConfirmations值为1,若任务配置无法生效,需检查节点是否加载了最新的任务文件:重启Chainlink节点,查看启动日志中是否有任务加载成功的提示。
  • 确认Operator合约是否支持动态读取任务配置中的minIncomingConfirmations,部分版本的Operator可能强制使用合约内配置值。

2. 核查自定义Bridge的可用性

  • 任务中使用了re-encrypt bridge,需确认该bridge的配置文件已放置在节点的bridges目录下,且对应服务正常运行。
  • 查看节点日志中fetch步骤的输出,确认是否成功从外部服务获取到reEncryptedData。若bridge调用失败,会直接中断后续流程。

3. 验证fulfillOracleRequest2的参数正确性

  • 核对encode_tx步骤中的callbackAddr是否为目标合约地址,而非Operator地址。
  • 计算fulfillReEncryption函数的选择器(web3.eth.abi.encodeFunctionSignature("fulfillReEncryption(bytes32,bytes)")取前4字节),与任务日志中的callbackFunctionId对比,确保两者一致。

4. 分析节点日志中的错误信息

  • 重点查看任务进入suspended状态时的日志:
    • 是否有ETH余额不足的提示(submit_tx需支付gas)?
    • 是否存在CBOR解码、JSON解析失败的报错?
    • 是否有LINK支付验证不通过的信息?

5. 确认权限配置完整性

  • 检查Operator合约是否被授权调用目标合约的fulfillReEncryption函数,部分场景下需显式给Operator合约授权。
  • 验证recordChainlinkFulfillment修饰器是否正确校验了请求发起方的权限,可通过日志确认请求ID的合法性。

6. 简化任务流程做测试

  • 暂时移除fetch和parse步骤,修改任务流程为decode_log -> encode_large -> encode_tx -> submit_tx,将encode_large中的_data设为固定bytes值。若此简化流程能触发fulfillReEncryption,则问题出在外部bridge服务或数据解析环节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:02:33