smartcontractkit / smartcontractkit/chainlink
[NODE] Job spec with multi-word response not calling fulfillment function
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 8.2k
- Forks
- 2k
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 202
Description
Description
I have a node running a job spec that attempts to build a multi-word response. On the node dashboard it reports a success but the callback function is never called. A similar issue can be found at https://stackoverflow.com/questions/70107436/chainlink-multi-variable-responses-smart-contract-request-not-fulfilled-by-oracl
Basic Information
- Network: Kovan
- Blockchain Client: Infura
- Go Version: Not sure
- Operating System: Ubuntu 20.04.3
- Commit: [log INFO line when starting node]
- Hosting Provider: Azure
- Startup Command:
cd ~/.chainlink-kovan && docker run -p 6688:6688 -v ~/.chainlink-kovan:/chainlink -it --env-file=.env --network host smartcontract/chainlink:1.0.0 local n - Smart contract calling the oracle:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "interfaces/ExternalBlockchainWalletCheckerInterface.sol";
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract BitcoinWalletChecker is
ExternalBlockchainWalletCheckerInterface,
ChainlinkClient
{
using Chainlink for Chainlink.Request;
bool private exists;
uint256 private balance;
uint256 private timestamp;
address private oracle;
bytes32 private jobId;
uint256 private fee;
event UpdatedWalletInfo(
string btc_wallet,
bool exists,
uint256 balance,
uint256 last_transaction
);
/**
* TODO: Make this parameterized and instantiate it to whichever network
* we are currently running on
* Network: Kovan
* Job webpage: https://market.link/jobs/10ce4dfb-ca85-4ffc-9849-772c2e8ae124
*/
constructor() {
setPublicChainlinkToken();
oracle = 0x745d8F7A8d25043C4e975c6A2578471F8f94388d;
jobId = "9e709ebdee48427eaa55c344a1362444"; // Get > BtcWalletInfo
fee = 1 * 10**18; // (Varies by network and job)
}
function updateWalletInfo(string calldata _btcWalletAddress)
external
returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(
jobId,
address(this),
this.fulfill.selector
);
request.add(
"get",
string(
bytes.concat(
bytes("https://lostcoin-function-app.azurewebsites.net/api/lostcoin-api?code=A3cVTg06CyiGd7FZlS647/OYppF2axary3dqtgPmP5Cy6Sc9emAcGQ==&wallet="),
bytes(_btcWalletAddress)
)
)
);
return sendChainlinkRequestTo(oracle, request, fee);
}
function fulfill(
bytes32 _requestId,
string calldata _btc_wallet,
uint256 _balance,
bool _exists,
uint256 _time_since_last_tx
) external recordChainlinkFulfillment(_requestId) {
exists = _exists;
balance = _balance;
timestamp = _time_since_last_tx;
emit UpdatedWalletInfo(_btc_wallet, exists, balance, timestamp);
}
function checkWalletInfo(string memory _walletAddress)
external
view
returns (
bool,
uint256,
uint256
)
{
// TODO: somehow get this to return the fulfillment result?
// It might be impossible - maybe we need to allow the caller of RequestWalletInfo to pass
// in a callback instead...
return (
exists,
balance,
/*age=*/
timestamp
);
}
}
- Job Spec:
type = "directrequest"
schemaVersion = 1
name = "Get > BtcWalletInfo"
contractAddress = "0x745d8F7A8d25043C4e975c6A2578471F8f94388d"
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)"]
decode_cbor [type="cborparse" data="$(decode_log.data)"]
fetch [type="http" method=GET url="$(decode_cbor.get)"]
parse_wallet [type="jsonparse" path="wallet" data="$(fetch)"]
parse_exist [type="jsonparse" path="exist" data="$(fetch)"]
parse_balance [type="jsonparse" path="balance" data="$(fetch)"]
parse_last_tx [type="jsonparse" path="last_transaction" data="$(fetch)"]
encode_data [type="ethabiencode" abi="fulfill(bytes32 _requestId, string calldata _btc_wallet, uint256 _balance, bool _exists, uint256 _time_since_last_tx)"
data="{\\"_requestId\\": $(decode_log.requestId), \\"_btc_wallet\\": $(parse_wallet), \\"_balance\\": $(parse_balance), \\"_exists\\": $(parse_exist), \\"_time_since_last_tx\\": $(parse_last_tx)}"]
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_data)}"
]
submit_tx [type="ethtx" to="0x745d8F7A8d25043C4e975c6A2578471F8f94388d" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch
fetch -> parse_wallet -> encode_data
fetch -> parse_exist -> encode_data
fetch -> parse_balance -> encode_data
fetch -> parse_last_tx -> encode_data
encode_data -> encode_tx -> submit_tx
"""
externalJobID = "9e709ebd-ee48-427e-aa55-c344a1362444"
- JSON output of job run:
{
"outputs": [
"{"logs": [], "root": "0x", "status": "0x0", "gasUsed": "0x6249", "blockHash": "0x971ae8460b21fc8966a720969ea49635b8a08833a62d2d6214ba816c8edce3a3", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x1b452c9", "contractAddress": "0x0000000000000000000000000000000000000000", "transactionHash": "0xecff4dac36d134257f28481c2442356c5ff70f916abb7ecde8c07859833df461", "transactionIndex": "0x8", "cumulativeGasUsed": "0x4ab2a"}"
],
"errors": [
null
],
"inputs": {
"jobRun": {
"logAddress": "0x745d8f7a8d25043c4e975c6a2578471f8f94388d",
"logBlockHash": "0xe76f4aabab2312ccf76752f8dc715cd06d2628621333146d62891ed551d5faef",
"logBlockNumber": 28594886,
"logData": "AAAAAAAAAAAAAAAA0ub2cG0U1tlKnaqNFhv6MBP9N493SjpKUCaIQg/sNfJdIpcxIQ2md810UzFlT56a9ePN2wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3gtrOnZAAAAAAAAAAAAAAAAAAA0ub2cG0U1tlKnaqNFhv6MBP9N4+3Kj95AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhpp1YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACuY2dldHioaHR0cHM6Ly9sb3N0Y29pbi1mdW5jdGlvbi1hcHAuYXp1cmV3ZWJzaXRlcy5uZXQvYXBpL2xvc3Rjb2luLWFwaT9jb2RlPUEzY1ZUZzA2Q3lpR2Q3RlpsUzY0Ny9PWXBwRjJheGFyeTNkcXRnUG1QNUN5NlNjOWVtQWNHUT09JndhbGxldD0xQTF6UDFlUDVRR2VmaTJETVBUZlRMNVNMbXY3RGl2Zk5hAAAAAAAAAAAAAAAAAAAAAAAA",
"logTopics": [
"0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65",
"0x3965373039656264656534383432376561613535633334346131333632343434"
],
"logTxHash": "0xa733880158ddf7bf701d3c82d7837d1ad1bf48bb0f80382802320b2cff5aef2a",
"meta": {
"oracleRequest": {
"callbackAddr": "0xD2e6f6706d14d6d94a9DAa8d161bFa3013FD378f",
"callbackFunctionId": "0xb72a3f79",
"cancelExpiration": "1638309208",
"data": "0x6367657478a868747470733a2f2f6c6f7374636f696e2d66756e6374696f6e2d6170702e617a75726577656273697465732e6e65742f6170692f6c6f7374636f696e2d6170693f636f64653d4133635654673036437969476437465a6c533634372f4f597070463261786172793364717467506d5035437936536339656d416347513d3d2677616c6c65743d3141317a5031655035514765666932444d505466544c35534c6d7637446976664e61",
"dataVersion": "1",
"payment": "1000000000000000000",
"requestId": "0x774a3a4a502688420fec35f25d229731210da677cd745331654f9e9af5e3cddb",
"requester": "0xD2e6f6706d14d6d94a9DAa8d161bFa3013FD378f",
"specId": "0x3965373039656264656534383432376561613535633334346131333632343434"
}
}
},
"jobSpec": {
"databaseID": 12,
"externalJobID": "9e709ebd-ee48-427e-aa55-c344a1362444",
"name": "Get > BtcWalletInfo"
}
},
"taskRuns": [
{
"type": "ethtx",
"createdAt": "2021-11-30T21:48:55.437038Z",
"finishedAt": "2021-11-30T21:51:31.437231Z",
"output": ""{\"logs\": [], \"root\": \"0x\", \"status\": \"0x0\", \"gasUsed\": \"0x6249\", \"blockHash\": \"0x971ae8460b21fc8966a720969ea49635b8a08833a62d2d6214ba816c8edce3a3\", \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\", \"blockNumber\": \"0x1b452c9\", \"contractAddress\": \"0x0000000000000000000000000000000000000000\", \"transactionHash\": \"0xecff4dac36d134257f28481c2442356c5ff70f916abb7ecde8c07859833df461\", \"transactionIndex\": \"0x8\", \"cumulativeGasUsed\": \"0x4ab2a\"}"",
"error": null,
"dotId": "submit_tx",
"status": "completed"
},
{
"type": "ethabidecodelog",
"createdAt": "2021-11-30T21:48:55.443702Z",
"finishedAt": "2021-11-30T21:48:55.444123Z",
"output": "{"callbackAddr":"0xd2e6f6706d14d6d94a9daa8d161bfa3013fd378f","callbackFunctionId":[183,42,63,121],"cancelExpiration":1638309208,"data":"Y2dldHioaHR0cHM6Ly9sb3N0Y29pbi1mdW5jdGlvbi1hcHAuYXp1cmV3ZWJzaXRlcy5uZXQvYXBpL2xvc3Rjb2luLWFwaT9jb2RlPUEzY1ZUZzA2Q3lpR2Q3RlpsUzY0Ny9PWXBwRjJheGFyeTNkcXRnUG1QNUN5NlNjOWVtQWNHUT09JndhbGxldD0xQTF6UDFlUDVRR2VmaTJETVBUZlRMNVNMbXY3RGl2Zk5h","dataVersion":1,"payment":1000000000000000000,"requestId":[119,74,58,74,80,38,136,66,15,236,53,242,93,34,151,49,33,13,166,119,205,116,83,49,101,79,158,154,245,227,205,219],"requester":"0xd2e6f6706d14d6d94a9daa8d161bfa3013fd378f","specId":[57,101,55,48,57,101,98,100,101,101,52,56,52,50,55,101,97,97,53,53,99,51,52,52,97,49,51,54,50,52,52,52]}",
"error": null,
"dotId": "decode_log",
"status": "completed"
},
{
"type": "cborparse",
"createdAt": "2021-11-30T21:48:55.444326Z",
"finishedAt": "2021-11-30T21:48:55.444535Z",
"output": "{"get":"https://lostcoin-function-app.azurewebsites.net/api/lostcoin-api?code=A3cVTg06CyiGd7FZlS647/OYppF2axary3dqtgPmP5Cy6Sc9emAcGQ==\u0026wallet=1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"}",
"error": null,
"dotId": "decode_cbor",
"status": "completed"
},
{
"type": "http",
"createdAt": "2021-11-30T21:48:55.444696Z",
"finishedAt": "2021-11-30T21:48:57.865101Z",
"output": ""{\"wallet\": \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\", \"exist\": true, \"balance\": 6852615533, \"last_transaction\": 1638278454}"",
"error": null,
"dotId": "fetch",
"status": "completed"
},
{
"type": "jsonparse",
"createdAt": "2021-11-30T21:48:57.865562Z",
"finishedAt": "2021-11-30T21:48:57.865892Z",
"output": ""1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"",
"error": null,
"dotId": "parse_wallet",
"status": "completed"
},
{
"type": "jsonparse",
"createdAt": "2021-11-30T21:48:57.865711Z",
"finishedAt": "2021-11-30T21:48:57.866468Z",
"output": "true",
"error": null,
"dotId": "parse_exist",
"status": "completed"
},
{
"type": "jsonparse",
"createdAt": "2021-11-30T21:48:57.866108Z",
"finishedAt": "2021-11-30T21:48:57.86633Z",
"output": "1638278454",
"error": null,
"dotId": "parse_last_tx",
"status": "completed"
},
{
"type": "jsonparse",
"createdAt": "2021-11-30T21:48:57.86648Z",
"finishedAt": "2021-11-30T21:48:57.866654Z",
"output": "6852615533",
"error": null,
"dotId": "parse_balance",
"status": "completed"
},
{
"type": "ethabiencode",
"createdAt": "2021-11-30T21:48:57.866766Z",
"finishedAt": "2021-11-30T21:48:57.867079Z",
"output": ""0xb72a3f79774a3a4a502688420fec35f25d229731210da677cd745331654f9e9af5e3cddb00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000198729d6d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000061a6253600000000000000000000000000000000000000000000000000000000000000223141317a5031655035514765666932444d505466544c35534c6d7637446976664e61000000000000000000000000000000000000000000000000000000000000"",
"error": null,
"dotId": "encode_data",
"status": "completed"
},
{
"type": "ethabiencode",
"createdAt": "2021-11-30T21:48:57.867146Z",
"finishedAt": "2021-11-30T21:48:57.867376Z",
"output": ""0x6ae0bc76774a3a4a502688420fec35f25d229731210da677cd745331654f9e9af5e3cddb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000d2e6f6706d14d6d94a9daa8d161bfa3013fd378fb72a3f79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061a69d5800000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000104b72a3f79774a3a4a502688420fec35f25d229731210da677cd745331654f9e9af5e3cddb00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000198729d6d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000061a6253600000000000000000000000000000000000000000000000000000000000000223141317a5031655035514765666932444d505466544c35534c6d7637446976664e6100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"",
"error": null,
"dotId": "encode_tx",
"status": "completed"
}
],
"createdAt": "2021-11-30T21:48:55.436149Z",
"finishedAt": "2021-11-30T21:51:31.44273Z",
"pipelineSpec": {
"id": 12,
"jobID": 0,
"dotDagSource": " 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="http" method=GET url="$(decode_cbor.get)"] parse_wallet [type="jsonparse" path="wallet" data="$(fetch)"] parse_exist [type="jsonparse" path="exist" data="$(fetch)"] parse_balance [type="jsonparse" path="balance" data="$(fetch)"] parse_last_tx [type="jsonparse" path="last_transaction" data="$(fetch)"] encode_data [type="ethabiencode" abi="fulfill(bytes32 _requestId, string calldata _btc_wallet, uint256 _balance, bool _exists, uint256 _time_since_last_tx)" data="{\"_requestId\": $(decode_log.requestId), \"_btc_wallet\": $(parse_wallet), \"_balance\": $(parse_balance), \"_exists\": $(parse_exist), \"_time_since_last_tx\": $(parse_last_tx)}"] 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_data)}" ] submit_tx [type="ethtx" to="0x745d8F7A8d25043C4e975c6A2578471F8f94388d" data="$(encode_tx)"] decode_log -> decode_cbor -> fetch fetch -> parse_wallet -> encode_data fetch -> parse_exist -> encode_data fetch -> parse_balance -> encode_data fetch -> parse_last_tx -> encode_data encode_data -> encode_tx -> submit_tx "
},
"id": "21",
"jobId": "12",
"status": "completed",
"type": "Pipeline job run"
}
Environment Variables
[replace this line with the output of the environment variables when running the node in debug mode]
Steps to Reproduce
- Set up node following instructions in https://docs.chain.link/docs/running-a-chainlink-node/
- Add the job spec provided above in the node dashboard
- Deploy the
BitcoinWalletCheckercontract (replacing the oracle address and jobId with those of the freshly deployed node) - Call checker.updateWalletInfo("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa") //any bitcoin address would do
- Wait for job run to complete in node dashboard
- Calling checker.checkWalletInfo("") /any string would do since the lookup is not implemented yet/ should return the values fetched by the job, but instead returns default zero values, suggesting the callback setting these values was never called.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Solidity fulfill function and the job spec's encode_data, encode_tx, and submit_tx tasks. Compare the multi-word _btc_wallet value with the completed ethtx output and transaction status, then trace whether the callback transaction reaches the contract. Done means the fulfillment callback executes and UpdatedWalletInfo is emitted for the supplied wallet response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, solidity
- Domain
- backend-api-design, blockchain
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100