From a5646bf840ebb0e1d976c9f1115c691a4f69f739 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Mon, 27 Nov 2023 18:40:36 -0800 Subject: [PATCH] [entropy] Add a default provider (#1150) * making a mess here * add default provider * cleanup * test new abi * add uri to fortuna * pr comments --- fortuna/Cargo.lock | 2 +- fortuna/src/abi.json | 646 ++++++++++-------- fortuna/src/command/register_provider.rs | 1 + fortuna/src/config/register_provider.rs | 6 + .../contracts/contracts/entropy/Entropy.sol | 24 +- .../contracts/entropy/EntropyState.sol | 1 + .../contracts/forge-test/Entropy.t.sol | 80 ++- .../entropy_sdk/solidity/EntropyStructs.sol | 4 + .../entropy_sdk/solidity/IEntropy.sol | 5 +- 9 files changed, 463 insertions(+), 306 deletions(-) diff --git a/fortuna/Cargo.lock b/fortuna/Cargo.lock index ef6ae7aa9..6788f703f 100644 --- a/fortuna/Cargo.lock +++ b/fortuna/Cargo.lock @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "fortuna" -version = "1.1.0" +version = "2.0.0" dependencies = [ "anyhow", "axum", diff --git a/fortuna/src/abi.json b/fortuna/src/abi.json index 13b4aa9b3..86175d036 100644 --- a/fortuna/src/abi.json +++ b/fortuna/src/abi.json @@ -1,482 +1,556 @@ [ { - "anonymous": false, + "type": "constructor", "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "feeInWei", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "accruedFeesInWei", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "originalCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "originalCommitmentSequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "commitmentMetadata", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "endSequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "currentCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "currentCommitmentSequenceNumber", - "type": "uint64" - } - ], - "indexed": false, - "internalType": "struct EntropyStructs.ProviderInfo", - "name": "provider", - "type": "tuple" - } - ], - "name": "Registered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "userCommitment", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "providerCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "providerCommitmentSequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - } - ], - "indexed": false, - "internalType": "struct EntropyStructs.Request", - "name": "request", - "type": "tuple" - } - ], - "name": "Requested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "userCommitment", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "providerCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "providerCommitmentSequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - } - ], - "indexed": false, - "internalType": "struct EntropyStructs.Request", - "name": "request", - "type": "tuple" + "name": "pythFeeInWei", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "bytes32", - "name": "userRevelation", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "providerRevelation", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "randomNumber", - "type": "bytes32" + "name": "defaultProvider", + "type": "address", + "internalType": "address" } ], - "name": "Revealed", - "type": "event" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "combineRandomValues", "inputs": [ { - "internalType": "bytes32", "name": "userRandomness", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes32", "name": "providerRandomness", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes32", "name": "blockHash", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "combineRandomValues", "outputs": [ { - "internalType": "bytes32", "name": "combinedRandomness", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "constructUserCommitment", "inputs": [ { - "internalType": "bytes32", "name": "userRandomness", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "constructUserCommitment", "outputs": [ { - "internalType": "bytes32", "name": "userCommitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { - "inputs": [], + "type": "function", "name": "getAccruedPythFees", + "inputs": [], "outputs": [ { - "internalType": "uint256", "name": "accruedPythFeesInWei", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "getDefaultProvider", + "inputs": [], + "outputs": [ { - "internalType": "address", "name": "provider", - "type": "address" + "type": "address", + "internalType": "address" } ], + "stateMutability": "view" + }, + { + "type": "function", "name": "getFee", + "inputs": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + } + ], "outputs": [ { - "internalType": "uint256", "name": "feeAmount", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "getProviderInfo", "inputs": [ { - "internalType": "address", "name": "provider", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "getProviderInfo", "outputs": [ { + "name": "info", + "type": "tuple", + "internalType": "struct EntropyStructs.ProviderInfo", "components": [ { - "internalType": "uint256", "name": "feeInWei", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "accruedFeesInWei", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", "name": "originalCommitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", "name": "originalCommitmentSequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes", "name": "commitmentMetadata", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "uri", + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "uint64", "name": "endSequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "uint64", "name": "sequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes32", "name": "currentCommitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", "name": "currentCommitmentSequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" } - ], - "internalType": "struct EntropyStructs.ProviderInfo", - "name": "info", - "type": "tuple" + ] } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "getRequest", "inputs": [ { - "internalType": "address", "name": "provider", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "uint64", "name": "sequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" } ], - "name": "getRequest", "outputs": [ { + "name": "req", + "type": "tuple", + "internalType": "struct EntropyStructs.Request", "components": [ { - "internalType": "address", "name": "provider", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "uint64", "name": "sequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes32", "name": "userCommitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes32", "name": "providerCommitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", "name": "providerCommitmentSequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "uint256", "name": "blockNumber", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "internalType": "struct EntropyStructs.Request", - "name": "req", - "type": "tuple" + ] } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "register", "inputs": [ { - "internalType": "uint256", "name": "feeInWei", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", "name": "commitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes", "name": "commitmentMetadata", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "uint64", "name": "chainLength", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "uri", + "type": "bytes", + "internalType": "bytes" } ], - "name": "register", "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "request", "inputs": [ { - "internalType": "address", "name": "provider", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", "name": "userCommitment", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bool", "name": "useBlockHash", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "name": "request", "outputs": [ { - "internalType": "uint64", "name": "assignedSequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" } ], - "stateMutability": "payable", - "type": "function" + "stateMutability": "payable" }, { + "type": "function", + "name": "reveal", "inputs": [ { - "internalType": "address", "name": "provider", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "uint64", "name": "sequenceNumber", - "type": "uint64" + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes32", "name": "userRandomness", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes32", "name": "providerRevelation", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "reveal", "outputs": [ { - "internalType": "bytes32", "name": "randomNumber", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "withdraw", "inputs": [ { - "internalType": "uint256", "name": "amount", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } ], - "name": "withdraw", "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Registered", + "inputs": [ + { + "name": "provider", + "type": "tuple", + "indexed": false, + "internalType": "struct EntropyStructs.ProviderInfo", + "components": [ + { + "name": "feeInWei", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accruedFeesInWei", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "originalCommitment", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "originalCommitmentSequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "commitmentMetadata", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "uri", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "endSequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "sequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "currentCommitment", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "currentCommitmentSequenceNumber", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Requested", + "inputs": [ + { + "name": "request", + "type": "tuple", + "indexed": false, + "internalType": "struct EntropyStructs.Request", + "components": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "sequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "userCommitment", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "providerCommitment", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "providerCommitmentSequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Revealed", + "inputs": [ + { + "name": "request", + "type": "tuple", + "indexed": false, + "internalType": "struct EntropyStructs.Request", + "components": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "sequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "userCommitment", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "providerCommitment", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "providerCommitmentSequenceNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "userRevelation", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "providerRevelation", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "blockHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "randomNumber", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AssertionFailure", + "inputs": [] + }, + { + "type": "error", + "name": "IncorrectProviderRevelation", + "inputs": [] + }, + { + "type": "error", + "name": "IncorrectUserRevelation", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientFee", + "inputs": [] + }, + { + "type": "error", + "name": "NoSuchProvider", + "inputs": [] + }, + { + "type": "error", + "name": "OutOfRandomness", + "inputs": [] } ] diff --git a/fortuna/src/command/register_provider.rs b/fortuna/src/command/register_provider.rs index 240ef25a1..fe7127fde 100644 --- a/fortuna/src/command/register_provider.rs +++ b/fortuna/src/command/register_provider.rs @@ -55,6 +55,7 @@ pub async fn register_provider(opts: &RegisterProviderOptions) -> Result<()> { commitment, bincode::serialize(&commitment_metadata)?.into(), commitment_length, + bincode::serialize(&opts.uri)?.into(), ) .send() .await? diff --git a/fortuna/src/config/register_provider.rs b/fortuna/src/config/register_provider.rs index 9fa3ed37a..c6281cdc6 100644 --- a/fortuna/src/config/register_provider.rs +++ b/fortuna/src/config/register_provider.rs @@ -36,4 +36,10 @@ pub struct RegisterProviderOptions { #[arg(long = "pyth-contract-fee")] #[arg(default_value = "100")] pub fee: U256, + + /// The URI where clients can retrieve random values from this provider, + /// i.e., wherever fortuna for this provider will be hosted. + #[arg(long = "uri")] + #[arg(default_value = "")] + pub uri: String, } diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index f7e0ffa72..37d886d25 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -72,19 +72,12 @@ import "./EntropyState.sol"; // protocol prior to the random number being revealed (i.e., prior to step (6) above). Integrators should ensure that // the user is always incentivized to reveal their random number, and that the protocol has an escape hatch for // cases where the user chooses not to reveal. -// -// TODOs: -// - governance?? -// - correct method access modifiers (public vs external) -// - gas optimizations -// - function to check invariants?? -// - need to increment pyth fees if someone transfers funds to the contract via another method -// - off-chain data ERC support? contract Entropy is IEntropy, EntropyState { // TODO: Use an upgradeable proxy - constructor(uint pythFeeInWei) { + constructor(uint pythFeeInWei, address defaultProvider) { _state.accruedPythFeesInWei = 0; _state.pythFeeInWei = pythFeeInWei; + _state.defaultProvider = defaultProvider; } // Register msg.sender as a randomness provider. The arguments are the provider's configuration parameters @@ -96,7 +89,8 @@ contract Entropy is IEntropy, EntropyState { uint feeInWei, bytes32 commitment, bytes calldata commitmentMetadata, - uint64 chainLength + uint64 chainLength, + bytes calldata uri ) public override { if (chainLength == 0) revert EntropyErrors.AssertionFailure(); @@ -117,6 +111,7 @@ contract Entropy is IEntropy, EntropyState { provider.currentCommitmentSequenceNumber = provider.sequenceNumber; provider.commitmentMetadata = commitmentMetadata; provider.endSequenceNumber = provider.sequenceNumber + chainLength; + provider.uri = uri; provider.sequenceNumber += 1; @@ -262,6 +257,15 @@ contract Entropy is IEntropy, EntropyState { info = _state.providers[provider]; } + function getDefaultProvider() + public + view + override + returns (address provider) + { + provider = _state.defaultProvider; + } + function getRequest( address provider, uint64 sequenceNumber diff --git a/target_chains/ethereum/contracts/contracts/entropy/EntropyState.sol b/target_chains/ethereum/contracts/contracts/entropy/EntropyState.sol index 1044c9726..fcc9e480a 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/EntropyState.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/EntropyState.sol @@ -8,6 +8,7 @@ contract EntropyInternalStructs { struct State { uint pythFeeInWei; uint accruedPythFeesInWei; + address defaultProvider; mapping(address => EntropyStructs.ProviderInfo) providers; mapping(bytes32 => EntropyStructs.Request) requests; } diff --git a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol index 1363de02b..c2490e34f 100644 --- a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol @@ -19,10 +19,13 @@ contract EntropyTest is Test { bytes32[] provider1Proofs; uint provider1FeeInWei = 8; uint64 provider1ChainLength = 100; + bytes provider1Uri = bytes("https://foo.com"); + bytes provider1CommitmentMetadata = hex"0100"; address public provider2 = address(2); bytes32[] provider2Proofs; uint provider2FeeInWei = 20; + bytes provider2Uri = bytes("https://bar.com"); address public user1 = address(3); address public user2 = address(4); @@ -32,7 +35,7 @@ contract EntropyTest is Test { bytes32 ALL_ZEROS = bytes32(uint256(0)); function setUp() public { - random = new Entropy(pythFeeInWei); + random = new Entropy(pythFeeInWei, provider1); bytes32[] memory hashChain1 = generateHashChain( provider1, @@ -44,14 +47,21 @@ contract EntropyTest is Test { random.register( provider1FeeInWei, provider1Proofs[0], - hex"0100", - provider1ChainLength + provider1CommitmentMetadata, + provider1ChainLength, + provider1Uri ); bytes32[] memory hashChain2 = generateHashChain(provider2, 0, 100); provider2Proofs = hashChain2; vm.prank(provider2); - random.register(provider2FeeInWei, provider2Proofs[0], hex"0200", 100); + random.register( + provider2FeeInWei, + provider2Proofs[0], + hex"0200", + 100, + provider2Uri + ); } function generateHashChain( @@ -59,7 +69,9 @@ contract EntropyTest is Test { uint64 startSequenceNumber, uint64 size ) public pure returns (bytes32[] memory hashChain) { - bytes32 initialValue = keccak256(abi.encodePacked(startSequenceNumber)); + bytes32 initialValue = keccak256( + abi.encodePacked(provider, startSequenceNumber) + ); hashChain = new bytes32[](size); for (uint64 i = 0; i < size; i++) { hashChain[size - (i + 1)] = initialValue; @@ -212,6 +224,31 @@ contract EntropyTest is Test { ); } + function testDefaultProvider() public { + uint64 sequenceNumber = request( + user2, + random.getDefaultProvider(), + 42, + false + ); + assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 0); + + assertRevealReverts( + random.getDefaultProvider(), + sequenceNumber, + 42, + provider2Proofs[sequenceNumber] + ); + + assertRevealSucceeds( + random.getDefaultProvider(), + sequenceNumber, + 42, + provider1Proofs[sequenceNumber], + ALL_ZEROS + ); + } + function testNoSuchProvider() public { assertRequestReverts(10000000, unregisteredProvider, 42, false); } @@ -318,7 +355,13 @@ contract EntropyTest is Test { 10 ); vm.prank(provider1); - random.register(provider1FeeInWei, newHashChain[0], hex"0100", 10); + random.register( + provider1FeeInWei, + newHashChain[0], + hex"0100", + 10, + provider1Uri + ); assertInvariants(); EntropyStructs.ProviderInfo memory info1 = random.getProviderInfo( provider1 @@ -387,7 +430,13 @@ contract EntropyTest is Test { // Check that overflowing the fee arithmetic causes the transaction to revert. vm.prank(provider1); - random.register(MAX_UINT256, provider1Proofs[0], hex"0100", 100); + random.register( + MAX_UINT256, + provider1Proofs[0], + hex"0100", + 100, + provider1Uri + ); vm.expectRevert(); random.getFee(provider1); } @@ -437,7 +486,13 @@ contract EntropyTest is Test { // Reregistering updates the required fees vm.prank(provider1); - random.register(12345, provider1Proofs[0], hex"0100", 100); + random.register( + 12345, + provider1Proofs[0], + hex"0100", + 100, + provider1Uri + ); assertRequestReverts(pythFeeInWei + 12345 - 1, provider1, 42, false); requestWithFee(user2, pythFeeInWei + 12345, provider1, 42, false); @@ -466,4 +521,13 @@ contract EntropyTest is Test { vm.expectRevert(); random.withdraw(providerOneBalance); } + + function testGetProviderInfo() public { + EntropyStructs.ProviderInfo memory providerInfo1 = random + .getProviderInfo(provider1); + // These two fields aren't used by the Entropy contract itself -- they're just convenient info to store + // on-chain -- so they aren't tested in the other tests. + assertEq(providerInfo1.uri, provider1Uri); + assertEq(providerInfo1.commitmentMetadata, provider1CommitmentMetadata); + } } diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol index 24bf575c3..dc011f926 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol @@ -21,6 +21,10 @@ contract EntropyStructs { // Metadata for the current commitment. Providers may optionally use this field to to help // manage rotations (i.e., to pick the sequence number from the correct hash chain). bytes commitmentMetadata; + // Optional URI where clients can retrieve revelations for the provider. + // Client SDKs can use this field to automatically determine how to retrieve random values for each provider. + // TODO: specify the API that must be implemented at this URI + bytes uri; // The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index). // The contract maintains the invariant that sequenceNumber <= endSequenceNumber. // If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values. diff --git a/target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol b/target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol index 1c597de8e..965b2cce1 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol @@ -13,7 +13,8 @@ interface IEntropy is EntropyEvents { uint feeInWei, bytes32 commitment, bytes calldata commitmentMetadata, - uint64 chainLength + uint64 chainLength, + bytes calldata uri ) external; // Withdraw a portion of the accumulated fees for the provider msg.sender. @@ -55,6 +56,8 @@ interface IEntropy is EntropyEvents { address provider ) external view returns (EntropyStructs.ProviderInfo memory info); + function getDefaultProvider() external view returns (address provider); + function getRequest( address provider, uint64 sequenceNumber