'Reverted transaction on Chainlink Node while fulfilling request

I am getting reverted transactions on my Chainlink node, and I am looking for some tips on how to debug it. The node picks up the Oracle request and the job runs successfully. My fulfill function is minimal:

function checkConditions(address _oracle, string memory _jobId) external {
    setPublicChainlinkToken();
    Chainlink.Request memory request = buildChainlinkRequest(
        stringToBytes32(_jobId),
        address(this),
        this.fulfill.selector
    );

    request.add("ytChannelId", "UCfpnY5NnBl-8L7SvICuYkYQ");
    sendChainlinkRequestTo(
        _oracle,
        request,
        1 * LINK_DIVISIBILITY
    );
}

event OnFulfill(uint256 _ytViews, uint256 _ytSubs);

function fulfill(
    bytes32 _requestId,
    uint256 _ytViews,
    uint256 _ytSubs
) public recordChainlinkFulfillment(_requestId) {
    emit OnFulfill(_ytViews, _ytSubs);
}

I adapted the jobspec from this github blob because it is a multi-variable job with a bridge, which is exactly my use-case. My .toml file:

type = "directrequest"
schemaVersion = 1
name = "mysocialcontract-ea-job"
contractAddress = "0x2Db11F9E1d0a1cDc4e3F4C75B4c14f4a4a1a3518"
maxTaskDuration = "0s"
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)"]
    decodecbor  [type="cborparse" data="$(decode_log.data)"]
    fetch  [type="bridge" name="mysocialcontract" requestData="{\\"id\\": \\"0\\", \\"data\\": {\\"ytChannelId\\": $(decodecbor.ytChannelId)}}"]
    decode_log -> decodecbor -> fetch
    ytSubs    [type=jsonparse path="result,ytSubs"]
    ytViews    [type=jsonparse path="result,ytViews"]
    fetch -> ytSubs 
    fetch -> ytViews
    ytSubs -> encode_mwr
    ytViews -> encode_mwr
    encode_mwr [type=ethabiencode abi="(bytes32 _requestId, uint256 _ytViews, uint256 _ytSubs)"
            data="{\\"_requestId\\": $(decode_log.requestId),\\"_ytViews\\": $(ytViews),\\"_ytSubs\\": $(ytSubs)}"]
    encode_tx [type=ethabiencode
            abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
            data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_mwr)}"]
    submit [type=ethtx to="0x2Db11F9E1d0a1cDc4e3F4C75B4c14f4a4a1a3518" data="$(encode_tx)" gasLimit="5000000"]
    encode_mwr -> encode_tx -> submit
"""

Transaction from one of the last attempts I ran: https://kovan.etherscan.io/tx/0x2b58d0b9c6a6718817acbfb4cfb1bdcc893b28cedf111a8b5293473842a9a9c3

This is my setup:

  • Chainlink node deployed on AWS.
  • My own bridge + external adapter.
  • A small function to test the Oracle on the Remix IDE with hardcoded values.


Solution 1:[1]

I managed to get the Multi-word request working thanks to a user on the Chainlink discord. The problem was, as he said, that I was using the Oracle.sol contract instead of the Operator.sol contract and then calling "fulfillOracleRequest2" on the node job. The problem was at the contract, not the .toml job. In fact, the only thing I ended up changing from the node job was the oracle address.

To get the contract working I just adapted the MultiWordConsumer.sol contract from the chainlink docs. I couldn't find much information about the Operator.sol contract on the Chainlink docs, so hopefully this will help people facing the same issue I had:

  • You have deploy your own Operator.sol contract instance. You can do so in Remix by creating a contracting that only imports the Operator.sol contract: import "@chainlink/contracts/src/v0.7/Operator.sol";

  • After deploying the Operator contract, you have to set your node as an authorized sender. You can do this by calling "setAuthorizedSenders" with your node's address, i.e. ["0xb7..."]

Solution 2:[2]

@fpluis wrote very good answer, that saved my time. In addition: if you deploy contracts on localnet (not testnet), remember this things:

  • use Operator.sol, not Oracle.sol
  • Operator->getAuthorizedSenders method, returns array, that contains your node addresses, if not exists, call Operator->setAuthorizedSenders with Node account addresses
  • your contracts for interaction with Operator contract (APIConsumer.sol in chainlink docs, by example) funded by LINK
  • Operator contract funded by LINK
  • Node account funded by ETH
  • Node job which jobId using in your contract for interaction, contains correct Operator contract address

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 fpluis
Solution 2 Alexandr