Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Votes should be hashed according to EIP-712 #335 #399

Merged
merged 6 commits into from
Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 130 additions & 58 deletions contracts/core/PollingPlace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,52 @@ contract PollingPlace is PollingPlaceInterface {
uint256 endHeight;
}

/** Vote message */
struct VoteMessage {

/** A unique identifier that identifies what chain this vote is about. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also explain here why it has to be part of the struct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the comment 👍

bytes20 coreIdentifier;

/**
* The hash of the transition object of the meta-block that would
* result from the source block being finalised and proposed to origin.
*/
bytes32 transitionHash;

/** The hash of the source block. */
bytes32 source;

/** The hash of the target block. */
bytes32 target;

/** The height of the source block. */
uint256 sourceHeight;

/** The height of the target block. */
uint256 targetHeight;
}

/** Vote object */
struct Vote {

/** Vote message. */
VoteMessage voteMessage;

/** v component of signature */
uint8 v;

/** r component of signature */
bytes32 r;

/** s component of signature */
bytes32 s;
}

/** To hash vote message according to EIP-712, a type hash is required. */
bytes32 constant VOTE_MESSAGE_TYPEHASH = keccak256(
"VoteMessage(bytes20 coreIdentifier,bytes32 transitionHash,bytes32 source,bytes32 target,uint256 sourceHeight,uint256 targetHeight)"
);

/* Public Variables */

/**
Expand Down Expand Up @@ -300,28 +346,27 @@ contract PollingPlace is PollingPlaceInterface {
BlockStoreInterface blockStore = blockStores[_coreIdentifier];
require(
address(blockStore) != address(0),
"The providede core identifier must be known to the PollingPlace."
"The provided core identifier must be known to the PollingPlace."
);

require(
blockStore.isVoteValid(_transitionHash, _source, _target),
"The provided vote is not valid according to the block store."
);

bytes32 voteHash = hashVote(
Vote memory voteObject = getVoteObject(
_coreIdentifier,
_transitionHash,
_source,
_target,
_sourceHeight,
_targetHeight
);
Validator storage validator = getValidatorFromVote(
voteHash,
_targetHeight,
_v,
_r,
_s
);
_s);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_s);
_s
);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!


Validator storage validator = getValidatorFromVote(voteObject);

require(validator.auxiliaryAddress != address(0), "Vote by unknown validator.");

require(
Expand All @@ -330,10 +375,7 @@ contract PollingPlace is PollingPlaceInterface {
);

storeVote(
voteHash,
_source,
_target,
_targetHeight,
voteObject,
validator,
blockStore
);
Expand Down Expand Up @@ -428,35 +470,29 @@ contract PollingPlace is PollingPlaceInterface {
* @dev All requirement checks must have been made before calling this
* method.
*
* @param _voteHash The hash of the vote object. The hash is used to
* identify the vote.
* @param _source The hash of the source checkpoint of the vote.
* @param _target The hash of the target checkpoint of the vote.
* @param _targetHeight The height of the target block of the vote.
* @param _validator The validator that signed the vote.
* @param _blockStore The block store that this vote is about.
* @param _voteObject Vote object.
*/
function storeVote(
bytes32 _voteHash,
bytes32 _source,
bytes32 _target,
uint256 _targetHeight,
Vote memory _voteObject,
Validator storage _validator,
BlockStoreInterface _blockStore
)
private
{
validatorTargetHeights[_validator.auxiliaryAddress] = _targetHeight;
votesWeights[_voteHash] += validatorWeight(_validator, currentMetaBlockHeight);
VoteMessage memory voteMessage = _voteObject.voteMessage;
bytes32 voteHash = hashVote(_voteObject.voteMessage);

validatorTargetHeights[_validator.auxiliaryAddress] = voteMessage.targetHeight;
votesWeights[voteHash] += validatorWeight(_validator, currentMetaBlockHeight);

/*
* Because the target must be within the currently open meta-block, the
* required weight must also be from the currently open meta-block.
*/
uint256 required = requiredWeight(currentMetaBlockHeight);

if (votesWeights[_voteHash] >= required) {
_blockStore.justify(_source, _target);
if (votesWeights[voteHash] >= required) {
_blockStore.justify(voteMessage.source, voteMessage.target);
}
}

Expand All @@ -482,25 +518,23 @@ contract PollingPlace is PollingPlaceInterface {
* @notice Uses the signature of a vote to recover the public address of
* the signer.
*
* @param _voteHash The hashed vote. It is the message that was signed.
* @param _v V of the signature.
* @param _r R of teh signature.
* @param _s S of the signature.
* @param _voteObject Vote object.
*
* @return The `Validator` that signed the given message with the given
* signature.
*/
function getValidatorFromVote(
bytes32 _voteHash,
uint8 _v,
bytes32 _r,
bytes32 _s
)
function getValidatorFromVote(Vote memory _voteObject)
private
view
returns (Validator storage validator_)
{
address signer = ecrecover(_voteHash, _v, _r, _s);
bytes32 voteHash = hashVote(_voteObject.voteMessage);
address signer = ecrecover(
voteHash,
_voteObject.v,
_voteObject.r,
_voteObject.s
);
validator_ = validators[signer];
}

Expand Down Expand Up @@ -564,35 +598,24 @@ contract PollingPlace is PollingPlaceInterface {
* @notice Creates the hash of o vote object. This is the same hash that
* the validator has signed.
*
* @param _coreIdentifier Core identifier of the vote object.
* @param _transitionHash Transition hash of the vote object.
* @param _source Source block hash of the vote object.
* @param _target Target block hash of the vote object.
* @param _sourceHeight Source height of the vote object.
* @param _targetHeight Target height of the vote object.
* @param _voteMessage Vote message object.
*
* @return The hash of the given vote.
*/
function hashVote(
bytes20 _coreIdentifier,
bytes32 _transitionHash,
bytes32 _source,
bytes32 _target,
uint256 _sourceHeight,
uint256 _targetHeight
)
function hashVote(VoteMessage memory _voteMessage)
private
pure
returns (bytes32 hashed_)
{
hashed_ = keccak256(
abi.encodePacked(
_coreIdentifier,
_transitionHash,
_source,
_target,
_sourceHeight,
_targetHeight
VOTE_MESSAGE_TYPEHASH,
_voteMessage.coreIdentifier,
_voteMessage.transitionHash,
_voteMessage.source,
_voteMessage.target,
_voteMessage.sourceHeight,
_voteMessage.targetHeight
)
);

Expand All @@ -605,4 +628,53 @@ contract PollingPlace is PollingPlaceInterface {
)
);
}

/**
* @notice Creates a vote object
*
* @param _coreIdentifier A unique identifier that identifies what chain
* this vote is about.
* @param _transitionHash The hash of the transition object of the
* meta-block that would result from the source
* block being finalised and proposed to origin.
* @param _source The hash of the source block.
* @param _target The hash of the target block.
* @param _sourceHeight The height of the source block.
* @param _targetHeight The height of the target block.
* @param _v V of the signature.
* @param _r R of the signature.
* @param _s S of the signature.
*
* @return vote object
*/
function getVoteObject(
bytes20 _coreIdentifier,
bytes32 _transitionHash,
bytes32 _source,
bytes32 _target,
uint256 _sourceHeight,
uint256 _targetHeight,
uint8 _v,
bytes32 _r,
bytes32 _s
)
private
returns (Vote memory voteObject_)
{
VoteMessage memory voteMessage = VoteMessage(
_coreIdentifier,
_transitionHash,
_source,
_target,
_sourceHeight,
_targetHeight
);

voteObject_ = Vote(
voteMessage,
_v,
_r,
_s
);
}
}
6 changes: 6 additions & 0 deletions test/core/PollingPlace.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const ValidatorIndexEnded = 2;
const ValidatorIndexStartHeight = 3;
const ValidatorIndexEndHeight = 4;

const VOTE_MESSAGE_TYPEHASH = web3.utils.sha3(
"VoteMessage(bytes20 coreIdentifier,bytes32 transitionHash,bytes32 source,bytes32 target,uint256 sourceHeight,uint256 targetHeight)"
);

contract('PollingPlace', async (accounts) => {
/*
* Make the first address the default meta-block gate to be able to
Expand Down Expand Up @@ -1071,7 +1075,9 @@ contract('PollingPlace', async (accounts) => {
* @returns {object} The signature of the vote (r, s, and v).
*/
async function signVote(address, vote) {

let voteDigest = web3.utils.soliditySha3(
{type: 'bytes32', value: VOTE_MESSAGE_TYPEHASH},
{type: 'bytes20', value: web3.utils.toChecksumAddress(vote.coreIdentifier)},
{type: 'bytes32', value: vote.transitionHash},
{type: 'bytes32', value: vote.source},
Expand Down