Solidity从数据库取实时数据及Oraclize实现白名单验证问询
问题2:实现isWhitelisted[msg.sender]映射,仅当用户钱包在SQL数据库中时返回true?
结合你提到的 Oraclize(Chainlink),这里有两种常见的实现思路,你可以根据需求选择:
思路1:预批量同步白名单
如果你的数据库中的白名单地址不会频繁变动,可以定期触发预言机批量查询数据库中的所有白名单地址,然后把这些地址批量标记到链上的isWhitelisted映射中。
这种方式的优点是用户后续验证时无需等待,直接查询链上映射即可;缺点是无法实时同步数据库的更新,需要手动或定时触发同步。
思路2:实时验证用户地址
如果需要实时验证用户地址是否在数据库中(比如数据库中的白名单随时可能更新),可以在用户需要验证白名单时,触发预言机请求,实时查询数据库并更新链上的映射状态。
具体实现步骤:
- 配置预言机和API:首先你需要搭建一个简单的 HTTP API,这个API接收预言机传来的用户地址参数,执行SQL查询(比如
SELECT EXISTS(SELECT 1 FROM whitelist WHERE wallet_address = '用户地址')),然后返回true或false。 - 合约集成预言机:参考问题1中的合约框架,编写一个函数让用户调用,发起针对自己地址的验证请求。
- 回调更新映射:预言机获取API返回的结果后,回调合约的函数,更新
isWhitelisted[msg.sender]的值。 - 白名单验证逻辑:在需要白名单权限的函数中,直接检查
isWhitelisted[msg.sender]是否为true。
示例代码片段:
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; contract WhitelistChecker is ChainlinkClient { using Chainlink for Chainlink.Request; address private oracle; bytes32 private jobId; uint256 private fee; // 白名单映射 mapping(address => bool) public isWhitelisted; constructor() { setPublicChainlinkToken(); oracle = 0xYourOracleAddress; jobId = "0xYourJobId"; // 对应HTTP GET请求的Job fee = 0.1 * 10 ** 18; } // 用户调用此函数,验证自己是否在白名单中 function checkMyWhitelistStatus() public returns (bytes32 requestId) { Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfillWhitelistCheck.selector); // 传递用户地址到API,比如API地址是https://yourapi.com/check-whitelist?address=xxx req.add("get", string(abi.encodePacked("https://yourapi.com/check-whitelist?address=", toString(msg.sender)))); req.add("path", "result"); // 假设API返回的JSON结构是{"result": true/false} return sendChainlinkRequestTo(oracle, req, fee); } // 预言机回调函数,更新白名单状态 function fulfillWhitelistCheck(bytes32 _requestId, bool _isWhitelisted) public recordChainlinkFulfillment(_requestId) { // 这里可以添加额外的验证,确保请求是针对msg.sender的(防止恶意回调) // 比如可以存储requestId和对应的地址,这里简化处理 isWhitelisted[msg.sender] = _isWhitelisted; } // 需要白名单权限的示例函数 function mintToken() public { require(isWhitelisted[msg.sender], "You are not whitelisted"); // 执行铸造逻辑... } function toString(address account) public pure returns (string memory) { return Strings.toHexString(uint256(uint160(account)), 20); } }
注意事项
- 费用问题:使用预言机需要支付服务费(Chainlink 用 LINK 代币),所以合约中需要预先存入足够的 LINK。
- 安全性:回调函数必须验证预言机的签名(Chainlink 的
recordChainlinkFulfillment修饰符已经帮你做了这部分),同时最好关联请求ID和发起请求的地址,防止恶意第三方触发回调。 - 延迟问题:实时验证会有一定的延迟,因为需要等待预言机节点处理请求、查询数据库并回调结果,所以如果你的业务对实时性要求极高,可能需要考虑预同步的方式。
内容的提问来源于stack exchange,提问作者Smiles Lt
相关产品推荐
相关产品推荐

