Updated contracts to support signature collection in side chain

This commit is contained in:
Kirill Fedoseev 2019-11-18 19:54:41 +03:00
parent 642ea4e9a5
commit 6606fbab35
5 changed files with 157 additions and 44 deletions

View File

@ -54,6 +54,7 @@ contract Bridge {
mapping(bytes32 => uint) public votesCount;
mapping(bytes32 => bool) public votes;
mapping(bytes32 => bool) public usedRange;
mapping(bytes32 => bool) public handledTx;
Status public status;
@ -146,9 +147,59 @@ contract Bridge {
emit ExchangeRequest(value, getNonce());
}
function transfer(bytes32 hash, address to, uint value) public readyOrClosing currentValidator {
if (tryVote(Vote.TRANSFER, hash, to, value)) {
tokenContract.transfer(to, value);
function transfer(bytes memory message, bytes memory signatures) public {
require(message.length == 116, "Incorrect message length");
require(signatures.length % 65 == 0, "Incorrect signatures length");
uint msgEpoch;
bytes32 msgId;
address msgTo;
uint msgValue;
assembly {
msgEpoch := mload(add(message, 32))
msgId := mload(add(message, 64))
msgTo := mload(add(message, 84))
msgValue := mload(add(message, 116))
}
require(msgEpoch <= epoch, "Invalid epoch number");
require(!handledTx[msgId], "Tx was already handled");
handledTx[msgId] = true;
address[] memory msgValidators = getValidatorsInEpoch(msgEpoch);
require(signatures.length / 65 >= getThreshold(msgEpoch), "Not enough signatures");
bytes32 msgHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n116", message));
bytes32 r;
bytes32 s;
uint8 v;
for (uint i = 0; i < signatures.length / 65; i++) {
uint offset = i * 65;
assembly {
r := mload(add(add(signatures,32),offset))
s := mload(add(add(signatures,64),offset))
v := byte(0, mload(add(add(signatures,96),offset)))
}
address signer = ecrecover(msgHash, v, r, s);
uint j;
for (j = 0; j < msgValidators.length; j++) {
if (msgValidators[j] == signer) {
delete msgValidators[j];
break;
}
}
require(j != msgValidators.length);
}
if (tokenContract.balanceOf(address(this)) >= msgValue) {
tokenContract.transfer(msgTo, msgValue);
} else {
tokenContract.approve(msgTo, msgValue);
}
}
@ -282,11 +333,15 @@ contract Bridge {
}
function getValidators() view public returns (address[] memory) {
return states[epoch].validators;
return getValidatorsInEpoch(epoch);
}
function getNextValidators() view public returns (address[] memory) {
return states[nextEpoch].validators;
return getValidatorsInEpoch(nextEpoch);
}
function getValidatorsInEpoch(uint _epoch) view public returns (address[] memory) {
return states[_epoch].validators;
}
function startVoting() public readyOrVoting currentValidator {

View File

@ -0,0 +1,17 @@
pragma solidity ^0.5.0;
contract KeyValueStorage {
mapping(bytes32 => bytes) public db;
function setData(bytes32 id, bytes32 key, bytes memory data) public {
db[encodeKey(msg.sender, id, key)] = data;
}
function getData(address from, bytes32 id, bytes32 key) view public returns (bytes memory) {
return db[encodeKey(from, id, key)];
}
function encodeKey(address sender, bytes32 id, bytes32 key) private pure returns (bytes32 hash) {
return keccak256(abi.encodePacked(sender, id, key));
}
}

View File

@ -1,42 +1,7 @@
pragma solidity ^0.5.0;
contract SharedDB {
mapping(bytes32 => bytes) public db;
mapping(bytes32 => uint) public signupsCount;
mapping(bytes32 => uint) public dbSignups;
import "./KeyValueStorage.sol";
import "./SignedMessageStorage.sol";
import "./SignupStorage.sol";
function signupSign(bytes32 hash) public {
require(dbSignups[keccak256(abi.encodePacked(msg.sender, hash))] == 0, "Already signuped");
dbSignups[keccak256(abi.encodePacked(msg.sender, hash))] = ++signupsCount[hash];
}
function getSignupNumber(bytes32 hash, address[] memory validators, address validator) view public returns (uint) {
if (dbSignups[keccak256(abi.encodePacked(validator, hash))] == 0)
return 0;
uint id = 1;
for (uint i = 0; i < validators.length; i++) {
uint vid = dbSignups[keccak256(abi.encodePacked(validators[i], hash))];
if (vid > 0 && vid < dbSignups[keccak256(abi.encodePacked(validator, hash))])
id++;
}
return id;
}
function getSignupAddress(bytes32 hash, address[] memory validators, uint signupNumber) view public returns (address) {
for (uint i = 0; i < validators.length; i++) {
if (getSignupNumber(hash, validators, validators[i]) == signupNumber) {
return validators[i];
}
}
return address(0);
}
function setData(bytes32 hash, bytes32 key, bytes memory data) public {
db[keccak256(abi.encodePacked(msg.sender, hash, key))] = data;
}
function getData(address from, bytes32 hash, bytes32 key) view public returns (bytes memory) {
return db[keccak256(abi.encodePacked(from, hash, key))];
}
}
contract SharedDB is KeyValueStorage, SignedMessageStorage, SignupStorage {}

View File

@ -0,0 +1,43 @@
pragma solidity ^0.5.0;
contract SignedMessageStorage {
struct SignedMessage {
bytes message;
mapping(address => bytes) signatures;
}
mapping(bytes32 => SignedMessage) signedMessages;
function addSignature(bytes memory message, bytes memory rsv) public {
require(message.length == 116, "Incorrect message length");
require(rsv.length == 65, "Incorrect signature length");
bytes32 msgHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n116", message));
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(rsv, 32))
s := mload(add(rsv, 64))
v := byte(0, mload(add(rsv, 96)))
}
require(ecrecover(msgHash, v, r, s) == msg.sender);
if (signedMessages[msgHash].message.length == 0) {
signedMessages[msgHash].message = message;
}
signedMessages[msgHash].signatures[msg.sender] = rsv;
}
function getSignatures(bytes32 msgHash, address[] memory validators) public view returns (bytes memory) {
bytes memory result;
for (uint i = 0; i < validators.length; i++) {
result = abi.encodePacked(result, signedMessages[msgHash].signatures[validators[i]]);
}
return result;
}
}

View File

@ -0,0 +1,33 @@
pragma solidity ^0.5.0;
contract SignupStorage {
mapping(bytes32 => uint) public signupsCount;
mapping(bytes32 => mapping(address => uint)) public signups;
function signup(bytes32 hash) public {
require(signups[hash][msg.sender] == 0, "Already signuped");
signups[hash][msg.sender] = ++signupsCount[hash];
}
function getSignupNumber(bytes32 hash, address[] memory validators, address validator) view public returns (uint) {
if (signups[hash][validator] == 0)
return 0;
uint id = 1;
for (uint i = 0; i < validators.length; i++) {
uint vid = signups[hash][validators[i]];
if (vid > 0 && vid < signups[hash][validator])
id++;
}
return id;
}
function getSignupAddress(bytes32 hash, address[] memory validators, uint signupNumber) view public returns (address) {
for (uint i = 0; i < validators.length; i++) {
if (getSignupNumber(hash, validators, validators[i]) == signupNumber) {
return validators[i];
}
}
return address(0);
}
}