Skip to content

Commit

Permalink
Use validator set precompiles in Attestations (#1248)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-chrzan authored Oct 22, 2019
1 parent 21f8cdc commit 273fc82
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 8 deletions.
38 changes: 38 additions & 0 deletions packages/protocol/contracts/common/UsingPrecompiles.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
pragma solidity ^0.5.3;


contract UsingPrecompiles {
/**
* @notice Gets a validator address from the current validator set.
* @param index Index of requested validator in the validator set as sorted by the election.
* @return Address of validator at the requested index.
*/
function validatorAddressFromCurrentSet(uint256 index) public view returns (address) {
address validatorAddress;
assembly {
let newCallDataPosition := mload(0x40)
mstore(newCallDataPosition, index)
let success := staticcall(5000, 0xfa, newCallDataPosition, 32, 0, 0)
returndatacopy(add(newCallDataPosition, 64), 0, 32)
validatorAddress := mload(add(newCallDataPosition, 64))
}

return validatorAddress;
}

/**
* @notice Gets the size of the current elected validator set.
* @return Size of the current elected validator set.
*/
function numberValidatorsInCurrentSet() public view returns (uint256) {
uint256 numberValidators;
assembly {
let success := staticcall(5000, 0xf9, 0, 0, 0, 0)
let returnData := mload(0x40)
returndatacopy(returnData, 0, 32)
numberValidators := mload(returnData)
}

return numberValidators;
}
}
15 changes: 12 additions & 3 deletions packages/protocol/contracts/identity/Attestations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ import "../governance/interfaces/IValidators.sol";
import "../common/Initializable.sol";
import "../common/UsingRegistry.sol";
import "../common/Signatures.sol";
import "../common/UsingPrecompiles.sol";


/**
* @title Contract mapping identifiers to accounts
*/
contract Attestations is IAttestations, Ownable, Initializable, UsingRegistry, ReentrancyGuard {
contract Attestations is
IAttestations,
Ownable,
Initializable,
UsingRegistry,
ReentrancyGuard,
UsingPrecompiles
{

using SafeMath for uint256;
using SafeMath for uint128;
Expand Down Expand Up @@ -739,15 +747,16 @@ contract Attestations is IAttestations, Ownable, Initializable, UsingRegistry, R
IRandom random = IRandom(registry.getAddressForOrDie(RANDOM_REGISTRY_ID));

bytes32 seed = random.random();
address[] memory validators = getElection().electValidators();
uint256 numberValidators = numberValidatorsInCurrentSet();

uint256 currentIndex = 0;
address validator;
address issuer;

while (currentIndex < n) {
seed = keccak256(abi.encodePacked(seed));
validator = validators[uint256(seed) % validators.length];
validator = validatorAddressFromCurrentSet(uint256(seed) % numberValidators);

issuer = getLockedGold().getAccountFromValidator(validator);
Attestation storage attestations =
state.issuedAttestations[issuer];
Expand Down
25 changes: 25 additions & 0 deletions packages/protocol/contracts/identity/test/TestAttestations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity ^0.5.3;

import "../Attestations.sol";


/*
* We need a test contract that behaves like the actual Attestations contract,
* but mocks the implementations of the validator set getters. Otherwise we
* couldn't test `request` with the current ganache local testnet.
*/
contract TestAttestations is Attestations {
address[] private __testValidators;

function __setValidators(address[] memory validators) public {
__testValidators = validators;
}

function numberValidatorsInCurrentSet() public view returns (uint256) {
return __testValidators.length;
}

function validatorAddressFromCurrentSet(uint256 index) public view returns (address) {
return __testValidators[index];
}
}
2 changes: 1 addition & 1 deletion packages/protocol/migrationsConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const linkedLibraries = {
AddressSortedLinkedList: ['Election'],
IntegerSortedLinkedList: ['Governance', 'IntegerSortedLinkedListTest'],
AddressSortedLinkedListWithMedian: ['SortedOracles', 'AddressSortedLinkedListWithMedianTest'],
Signatures: ['Attestations', 'LockedGold', 'Escrow'],
Signatures: ['TestAttestations', 'Attestations', 'LockedGold', 'Escrow'],
}

const argv = minimist(process.argv.slice(2), {
Expand Down
14 changes: 10 additions & 4 deletions packages/protocol/test/identity/attestations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { getPhoneHash } from '@celo/utils/lib/phoneNumbers'
import BigNumber from 'bignumber.js'
import { uniq } from 'lodash'
import {
AttestationsContract,
AttestationsInstance,
TestAttestationsContract,
TestAttestationsInstance,
MockLockedGoldContract,
MockLockedGoldInstance,
MockStableTokenContract,
Expand All @@ -28,7 +28,12 @@ import {
} from 'types'
import { getParsedSignatureOfAddress } from '../../lib/signing-utils'

const Attestations: AttestationsContract = artifacts.require('Attestations')
/* We use a contract that behaves like the actual Attestations contract, but
* mocks the implementations of validator set getters. These rely on precompiled
* contracts, which are not available in our current ganache fork, which we use
* for Truffle unit tests.
*/
const Attestations: TestAttestationsContract = artifacts.require('TestAttestations')
const MockStableToken: MockStableTokenContract = artifacts.require('MockStableToken')
const MockElection: MockElectionContract = artifacts.require('MockElection')
const MockLockedGold: MockLockedGoldContract = artifacts.require('MockLockedGold')
Expand All @@ -41,7 +46,7 @@ const longDataEncryptionKey =
'02f2f48ee19680706196e2e339e5da3491186e0c4c5030670656b0e01611111111'

contract('Attestations', (accounts: string[]) => {
let attestations: AttestationsInstance
let attestations: TestAttestationsInstance
let mockStableToken: MockStableTokenInstance
let otherMockStableToken: MockStableTokenInstance
let random: RandomInstance
Expand Down Expand Up @@ -157,6 +162,7 @@ contract('Attestations', (accounts: string[]) => {
[mockStableToken.address, otherMockStableToken.address],
[attestationFee, attestationFee]
)
await attestations.__setValidators(accounts)
})

describe('#initialize()', () => {
Expand Down

0 comments on commit 273fc82

Please sign in to comment.