1.VRFConsumerBase

  1. pragma solidity ^0.6.0;
  2. import "./vendor/SafeMathChainlink.sol";
  3. import "./interfaces/LinkTokenInterface.sol";
  4. import "./VRFRequestIDBase.sol";
  5. abstract contract VRFConsumerBase is VRFRequestIDBase {
  6. using SafeMathChainlink for uint256;
  7. /**
  8. * @notice fulfillRandomness handles the VRF response. Your contract must
  9. * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
  10. * @notice principles to keep in mind when implementing your fulfillRandomness
  11. * @notice method.
  12. *
  13. * @dev VRFConsumerBase expects its subcontracts to have a method with this
  14. * @dev signature, and will call it once it has verified the proof
  15. * @dev associated with the randomness. (It is triggered via a call to
  16. * @dev rawFulfillRandomness, below.)
  17. *
  18. * @param requestId The Id initially returned by requestRandomness
  19. * @param randomness the VRF output
  20. */
  21. function fulfillRandomness(bytes32 requestId, uint256 randomness)
  22. internal virtual;
  23. uint256 constant private USER_SEED_PLACEHOLDER = 0;
  24. function requestRandomness(bytes32 _keyHash, uint256 _fee)
  25. internal returns (bytes32 requestId)
  26. {
  27. LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER));
  28. // This is the seed passed to VRFCoordinator. The oracle will mix this with
  29. // the hash of the block containing this request to obtain the seed/input
  30. // which is finally passed to the VRF cryptographic machinery.
  31. uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]);
  32. // nonces[_keyHash] must stay in sync with
  33. // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
  34. // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest).
  35. // This provides protection against the user repeating their input seed,
  36. // which would result in a predictable/duplicate output, if multiple such
  37. // requests appeared in the same block.
  38. nonces[_keyHash] = nonces[_keyHash].add(1);
  39. return makeRequestId(_keyHash, vRFSeed);
  40. }
  41. LinkTokenInterface immutable internal LINK;
  42. address immutable private vrfCoordinator;
  43. // Nonces for each VRF key from which randomness has been requested.
  44. //
  45. // Must stay in sync with VRFCoordinator[_keyHash][this]
  46. mapping(bytes32 /* keyHash */ => uint256 /* nonce */) private nonces;
  47. /**
  48. * @param _vrfCoordinator address of VRFCoordinator contract
  49. * @param _link address of LINK token contract
  50. *
  51. * @dev https://docs.chain.link/docs/link-token-contracts
  52. */
  53. constructor(address _vrfCoordinator, address _link) public {
  54. vrfCoordinator = _vrfCoordinator;
  55. LINK = LinkTokenInterface(_link);
  56. }
  57. // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
  58. // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
  59. // the origin of the call
  60. function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external {
  61. require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
  62. fulfillRandomness(requestId, randomness);
  63. }
  64. }

1. requestRandomnessfunction requestRandomness

执行流程:
1).需要向vrfCoordinator 转账link ,同时向
2)生成传递给 VRCoordinator 的种子。oracle 会将其与包含此请求的块的哈希混合,以获得最终传递给 VRF 加密机制的种子/输入。
3) nonces[_keyHash] 必须与 VRCoordinator.nonces[_keyHash][this] 保持同步,它由上述成功的 LINK.transferAndCall(在 VRCoordinator.randomnessRequest 中)增加。 这提供了防止用户重复输入种子的保护,如果多个此类请求出现在同一块中,这将导致可预测/重复的输出。

  1. function requestRandomness(bytes32 _keyHash, uint256 _fee)
  2. internal returns (bytes32 requestId)
  3. {
  4. LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER));
  5. // This is the seed passed to VRFCoordinator. The oracle will mix this with
  6. // the hash of the block containing this request to obtain the seed/input
  7. // which is finally passed to the VRF cryptographic machinery.
  8. uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]);
  9. //nonces[_keyHash] 必须与 VRCoordinator.nonces[_keyHash][this] 保持同步,它由上述成功的 LINK.transferAndCall(在 VRCoordinator.randomnessRequest 中)增加。
  10. // 这提供了防止用户重复输入种子的保护,如果多个此类请求出现在同一块中,这将导致可预测/重复的输出。
  11. nonces[_keyHash] = nonces[_keyHash].add(1);
  12. return makeRequestId(_keyHash, vRFSeed);
  13. }
  14. LinkTokenInterface immutable internal LINK;

2. VRFCoordinatoris

请求时触发的事件

event emit RandomnessRequest(_keyHash, preSeed, serviceAgreements[_keyHash].jobID, _sender, _feePaid, requestId);

将随机数返回时触发的事件

emit RandomnessRequestFulfilled(requestId, randomness);

  1. contract VRFCoordinator is VRF, VRFRequestIDBase, Ownable {
  2. struct Callback { // Tracks an ongoing request
  3. address callbackContract; // Requesting contract, which will receive response
  4. // Amount of LINK paid at request time. Total LINK = 1e9 * 1e18 < 2^96, so
  5. // this representation is adequate, and saves a word of storage when this
  6. // field follows the 160-bit callbackContract address.
  7. uint96 randomnessFee;
  8. // Commitment to seed passed to oracle by this contract, and the number of
  9. // the block in which the request appeared. This is the keccak256 of the
  10. // concatenation of those values. Storing this commitment saves a word of
  11. // storage.
  12. bytes32 seedAndBlockNum;
  13. }
  14. function randomnessRequest(
  15. bytes32 _keyHash,
  16. uint256 _consumerSeed,
  17. uint256 _feePaid,
  18. address _sender
  19. )
  20. internal
  21. sufficientLINK(_feePaid, _keyHash)
  22. {
  23. uint256 nonce = nonces[_keyHash][_sender];
  24. uint256 preSeed = makeVRFInputSeed(_keyHash, _consumerSeed, _sender, nonce);
  25. bytes32 requestId = makeRequestId(_keyHash, preSeed);
  26. // Cryptographically guaranteed by preSeed including an increasing nonce
  27. assert(callbacks[requestId].callbackContract == address(0));
  28. callbacks[requestId].callbackContract = _sender;
  29. assert(_feePaid < 1e27); // Total LINK fits in uint96
  30. callbacks[requestId].randomnessFee = uint96(_feePaid);
  31. callbacks[requestId].seedAndBlockNum = keccak256(abi.encodePacked(
  32. preSeed, block.number));
  33. emit RandomnessRequest(_keyHash, preSeed, serviceAgreements[_keyHash].jobID,
  34. _sender, _feePaid, requestId);
  35. nonces[_keyHash][_sender] = nonces[_keyHash][_sender].add(1);
  36. }
  37. function fulfillRandomnessRequest(bytes memory _proof) public {
  38. (bytes32 currentKeyHash, Callback memory callback, bytes32 requestId,
  39. uint256 randomness) = getRandomnessFromProof(_proof);
  40. // Pay oracle
  41. address oadd = serviceAgreements[currentKeyHash].vRFOracle;
  42. withdrawableTokens[oadd] = withdrawableTokens[oadd].add(
  43. callback.randomnessFee);
  44. // Forget request. Must precede callback (prevents reentrancy)
  45. delete callbacks[requestId];
  46. callBackWithRandomness(requestId, randomness, callback.callbackContract);
  47. emit RandomnessRequestFulfilled(requestId, randomness);
  48. }
  49. }