使用 Operator.sol 合约的 Solidity 智能合约未调用 Chainlink 作业
Chainlink job is not being called by the Solidity Smart Contract using Operator.sol contract
当使用 Oracle.sol
合约的 Solidity 智能合约调用时,正在成功触发并完成在 Chainlink 节点上部署和 运行 的作业规范。
但是,由于要求是 return 大响应 (https://docs.chain.link/docs/large-responses/),所以我不得不使用 Operator.sol
合同而不是 Oracle.sol
。然后,作业未被调用。
已部署的 Operator 合约如下所示:
我用来部署 Operator.sol
合约的 LINK 令牌和所有者地址是:
LINK 代币地址基本上取自官方 Chainlink 文档 (https://docs.chain.link/docs/fulfilling-requests/),其中提到了 Kovan Testnet LINK 代币地址:
所有者地址取自 运行 Chainlink 节点的账户地址:
Solidity智能合约代码为:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
bytes public data;
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D);
}
function requestBytes(
)
public
{
bytes32 specId = "a3d1b2c945244e44bdb412c5b5287df3";
uint256 payment = 100000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("data", "{\"agg_x\": \"agg_mean\", \"dataset_code\":\"MODIS/006/MOD14A1\", \"selected_band\":\"MaxFRP\", \"image_scale\":1000, \"start_date\":\"2021-09-01\", \"end_date\":\"2021-09-10\", \"geometry\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"id\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[29.53125,19.642587534013032],[29.53125,27.059125784374068],[39.90234375,27.059125784374068],[39.90234375,19.642587534013032],[29.53125,19.642587534013032]]]}},{\"type\":\"Feature\",\"properties\":{\"id\":2},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[46.40625,13.752724664396988],[46.40625,20.138470312451155],[56.25,20.138470312451155],[56.25,13.752724664396988],[46.40625,13.752724664396988]]]}}]}}");
sendOperatorRequest(req, payment);
}
function fulfillBytes(
bytes32 requestId,
bytes memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
data = bytesData;
}
}
合约编译部署成功。但是 requestBytes
函数无法在 Chainlink 节点上触发作业规范 运行。
PS: 正在使用Oracle.sol
的类似智能合约的功能成功触发了job-spec。
Chainlink 节点上的 TOML 作业规范 运行 是:
type = "directrequest"
schemaVersion = 1
name = "shamba-fire-data"
contractAddress = "0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D"
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="bridge" name="shamba-fire-bridge" requestData="{\"id\": $(jobSpec.externalJobID), \"data\":$(decode_cbor.data)}"]
parse [type="jsonparse" path="result,1,0" data="$(fetch)"]
encode_data [type="ethabiencode" abi="(uint256 value)" data="{ \"value\": $(parse) }"]
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="0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "a3d1b2c9-4524-4e44-bdb4-12c5b5287df3"
谁能给我指出正确的方向,比如我在这些步骤中做错了什么导致智能合约无法触发作业规范?
首先,Operator.sol
的所有者地址应该是进行交易的 Metamask 钱包 Kovan 测试网地址(而不是 运行 Chainlink 节点的帐户地址) .
然后Operator.sol
部署成功后,调用Operator.sol
的setAuthorizedSenders
函数,传入运行Chainlink节点的账户地址发件人 address[]
字段如:
那么,job-spec 的 encode_data
也应该有 requestId
参数:
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256[][] value)" data="{ \"requestId\": $(decode_log.requestId), \"value\": $(parse) }"]
整个job-spec应该是:
type = "directrequest"
schemaVersion = 1
name = "shamba-fire-data"
contractAddress = "0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F"
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="bridge" name="shamba-fire-bridge" requestData="{\"id\": $(jobSpec.externalJobID), \"data\":$(decode_cbor.data)}"]
parse [type="jsonparse" path="result" data="$(fetch)"]
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256[][] value)" data="{ \"requestId\": $(decode_log.requestId), \"value\": $(parse) }"]
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="0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "66229880-79e1-43c6-9d9e-0eb4b668729d"
同理,solidity智能合约代码应该是:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256[][] public data;
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F);
}
function requestBytes(
)
public
{
bytes32 specId = "6622988079e143c69d9e0eb4b668729d";
//0x3065666666656632313564353466316339663332623636376466613061346536;
uint256 payment = 1000000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("data", "{\"agg_x\": \"agg_mean\", \"dataset_code\":\"MODIS/006/MOD14A1\", \"selected_band\":\"MaxFRP\", \"image_scale\":1000, \"start_date\":\"2021-09-01\", \"end_date\":\"2021-09-10\", \"geometry\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"id\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[29.53125,19.642587534013032],[29.53125,27.059125784374068],[39.90234375,27.059125784374068],[39.90234375,19.642587534013032],[29.53125,19.642587534013032]]]}},{\"type\":\"Feature\",\"properties\":{\"id\":2},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[46.40625,13.752724664396988],[46.40625,20.138470312451155],[56.25,20.138470312451155],[56.25,13.752724664396988],[46.40625,13.752724664396988]]]}}]}}");
sendOperatorRequest(req, payment);
}
function fulfillBytes(
bytes32 requestId,
uint256[][] memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
data = bytesData;
}
}
当使用 Oracle.sol
合约的 Solidity 智能合约调用时,正在成功触发并完成在 Chainlink 节点上部署和 运行 的作业规范。
但是,由于要求是 return 大响应 (https://docs.chain.link/docs/large-responses/),所以我不得不使用 Operator.sol
合同而不是 Oracle.sol
。然后,作业未被调用。
已部署的 Operator 合约如下所示:
我用来部署 Operator.sol
合约的 LINK 令牌和所有者地址是:
LINK 代币地址基本上取自官方 Chainlink 文档 (https://docs.chain.link/docs/fulfilling-requests/),其中提到了 Kovan Testnet LINK 代币地址:
所有者地址取自 运行 Chainlink 节点的账户地址:
Solidity智能合约代码为:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
bytes public data;
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D);
}
function requestBytes(
)
public
{
bytes32 specId = "a3d1b2c945244e44bdb412c5b5287df3";
uint256 payment = 100000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("data", "{\"agg_x\": \"agg_mean\", \"dataset_code\":\"MODIS/006/MOD14A1\", \"selected_band\":\"MaxFRP\", \"image_scale\":1000, \"start_date\":\"2021-09-01\", \"end_date\":\"2021-09-10\", \"geometry\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"id\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[29.53125,19.642587534013032],[29.53125,27.059125784374068],[39.90234375,27.059125784374068],[39.90234375,19.642587534013032],[29.53125,19.642587534013032]]]}},{\"type\":\"Feature\",\"properties\":{\"id\":2},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[46.40625,13.752724664396988],[46.40625,20.138470312451155],[56.25,20.138470312451155],[56.25,13.752724664396988],[46.40625,13.752724664396988]]]}}]}}");
sendOperatorRequest(req, payment);
}
function fulfillBytes(
bytes32 requestId,
bytes memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
data = bytesData;
}
}
合约编译部署成功。但是 requestBytes
函数无法在 Chainlink 节点上触发作业规范 运行。
PS: 正在使用Oracle.sol
的类似智能合约的功能成功触发了job-spec。
Chainlink 节点上的 TOML 作业规范 运行 是:
type = "directrequest"
schemaVersion = 1
name = "shamba-fire-data"
contractAddress = "0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D"
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="bridge" name="shamba-fire-bridge" requestData="{\"id\": $(jobSpec.externalJobID), \"data\":$(decode_cbor.data)}"]
parse [type="jsonparse" path="result,1,0" data="$(fetch)"]
encode_data [type="ethabiencode" abi="(uint256 value)" data="{ \"value\": $(parse) }"]
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="0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "a3d1b2c9-4524-4e44-bdb4-12c5b5287df3"
谁能给我指出正确的方向,比如我在这些步骤中做错了什么导致智能合约无法触发作业规范?
首先,Operator.sol
的所有者地址应该是进行交易的 Metamask 钱包 Kovan 测试网地址(而不是 运行 Chainlink 节点的帐户地址) .
然后Operator.sol
部署成功后,调用Operator.sol
的setAuthorizedSenders
函数,传入运行Chainlink节点的账户地址发件人 address[]
字段如:
那么,job-spec 的 encode_data
也应该有 requestId
参数:
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256[][] value)" data="{ \"requestId\": $(decode_log.requestId), \"value\": $(parse) }"]
整个job-spec应该是:
type = "directrequest"
schemaVersion = 1
name = "shamba-fire-data"
contractAddress = "0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F"
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="bridge" name="shamba-fire-bridge" requestData="{\"id\": $(jobSpec.externalJobID), \"data\":$(decode_cbor.data)}"]
parse [type="jsonparse" path="result" data="$(fetch)"]
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256[][] value)" data="{ \"requestId\": $(decode_log.requestId), \"value\": $(parse) }"]
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="0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "66229880-79e1-43c6-9d9e-0eb4b668729d"
同理,solidity智能合约代码应该是:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256[][] public data;
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F);
}
function requestBytes(
)
public
{
bytes32 specId = "6622988079e143c69d9e0eb4b668729d";
//0x3065666666656632313564353466316339663332623636376466613061346536;
uint256 payment = 1000000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("data", "{\"agg_x\": \"agg_mean\", \"dataset_code\":\"MODIS/006/MOD14A1\", \"selected_band\":\"MaxFRP\", \"image_scale\":1000, \"start_date\":\"2021-09-01\", \"end_date\":\"2021-09-10\", \"geometry\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"id\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[29.53125,19.642587534013032],[29.53125,27.059125784374068],[39.90234375,27.059125784374068],[39.90234375,19.642587534013032],[29.53125,19.642587534013032]]]}},{\"type\":\"Feature\",\"properties\":{\"id\":2},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[46.40625,13.752724664396988],[46.40625,20.138470312451155],[56.25,20.138470312451155],[56.25,13.752724664396988],[46.40625,13.752724664396988]]]}}]}}");
sendOperatorRequest(req, payment);
}
function fulfillBytes(
bytes32 requestId,
uint256[][] memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
data = bytesData;
}
}