test: adds tests and fixes to home contract (#38)

* lint: run prettier on js tests and scripts

* tests: add 100% test coverage for the queue contract

* test: adds halt on failed state and in progress test on accepting updates

* fix: Updater.signUpdate now hashes message with Ethereum prefix before signing

* fix: fixed off-by-one error in queue contains() where for loop wasn't visiting _q.last

* fix: fix equality logic for double update check in Common.sol

* feature: adds tests for skipping current root and submitting update with non-existent new root

* test: adds test that ensures rejection of updates from fake updater

* test: adds double update test

* refactor: adds enqueueMessageAndSuggestUpdate helper function to shorten tests

* test: adds test for suggested updates

* refactor: changes doubleUpdate function to take single oldRoot rather than array

* refactor: Home test helper function enqueues message and returns its root rather than both current and new root

* refactor: moved queueContains and queueEnd from TestHome to QueueManager contract

* refactor: moves signer and updater initialization to before block, now updater creation uses async static fromSigner

Co-authored-by: James Prestwich <prestwich@clabs.co>
buddies-main-deployment
Luke Tchang 4 years ago committed by James Prestwich
parent e5cdfd85e5
commit 7cc25a9cbd
No known key found for this signature in database
GPG Key ID: 7CC174C250AD83AD
  1. 40
      rust/optics-base/src/abis/Home.abi.json
  2. 44
      rust/optics-base/src/abis/ProcessingReplica.abi.json
  3. 14
      solidity/contracts/Common.sol
  4. 6
      solidity/contracts/Home.sol
  5. 10
      solidity/contracts/Queue.sol
  6. 15
      solidity/contracts/test/TestHome.sol
  7. 14
      solidity/contracts/test/TestQueue.sol
  8. 7
      solidity/lib/index.js
  9. 369
      solidity/package-lock.json
  10. 6
      solidity/package.json
  11. 132
      solidity/test/Home.test.js

@ -51,9 +51,9 @@
"inputs": [
{
"indexed": false,
"internalType": "bytes32[2]",
"internalType": "bytes32",
"name": "_oldRoot",
"type": "bytes32[2]"
"type": "bytes32"
},
{
"indexed": false,
@ -143,9 +143,9 @@
{
"inputs": [
{
"internalType": "bytes32[2]",
"internalType": "bytes32",
"name": "_oldRoot",
"type": "bytes32[2]"
"type": "bytes32"
},
{
"internalType": "bytes32[2]",
@ -233,6 +233,38 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_item",
"type": "bytes32"
}
],
"name": "queueContains",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "queueEnd",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "root",

@ -40,9 +40,9 @@
"inputs": [
{
"indexed": false,
"internalType": "bytes32[2]",
"internalType": "bytes32",
"name": "_oldRoot",
"type": "bytes32[2]"
"type": "bytes32"
},
{
"indexed": false,
@ -178,9 +178,9 @@
{
"inputs": [
{
"internalType": "bytes32[2]",
"internalType": "bytes32",
"name": "_oldRoot",
"type": "bytes32[2]"
"type": "bytes32"
},
{
"internalType": "bytes32[2]",
@ -317,12 +317,12 @@
"outputs": [
{
"internalType": "bool",
"name": "",
"name": "_success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "",
"name": "_ret",
"type": "bytes"
}
],
@ -386,6 +386,38 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_item",
"type": "bytes32"
}
],
"name": "queueContains",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "queueEnd",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "state",

@ -98,7 +98,7 @@ abstract contract Common {
bytes signature
);
event DoubleUpdate(
bytes32[2] _oldRoot,
bytes32 _oldRoot,
bytes32[2] _newRoot,
bytes _signature,
bytes _signature2
@ -123,7 +123,7 @@ abstract contract Common {
}
modifier notFailed() {
require(state != States.FAILED);
require(state != States.FAILED, "failed state");
_;
}
@ -138,16 +138,18 @@ abstract contract Common {
return ECDSA.recover(_digest, _signature) == updater;
}
// Checks that updater signed both updates and that
// the two updates are not equal (i.e. conflicting)
function doubleUpdate(
bytes32[2] calldata _oldRoot,
bytes32 _oldRoot,
bytes32[2] calldata _newRoot,
bytes calldata _signature,
bytes calldata _signature2
) external notFailed {
if (
Common.checkSig(_newRoot[0], _oldRoot[0], _signature) &&
Common.checkSig(_newRoot[1], _oldRoot[1], _signature2) &&
(_newRoot[0] != _newRoot[1] || _oldRoot[0] != _oldRoot[1])
Common.checkSig(_oldRoot, _newRoot[0], _signature) &&
Common.checkSig(_oldRoot, _newRoot[1], _signature2) &&
_newRoot[0] != _newRoot[1]
) {
fail();
emit DoubleUpdate(_oldRoot, _newRoot, _signature, _signature2);

@ -66,7 +66,7 @@ contract Home is MerkleTreeManager, QueueManager, Common {
bytes32 _newRoot,
bytes memory _signature
) external notFailed {
if (improperUpdate(_newRoot, _oldRoot, _signature)) return;
if (improperUpdate(_oldRoot, _newRoot, _signature)) return;
while (true) {
bytes32 next = queue.dequeue();
if (next == _newRoot) break;
@ -79,8 +79,8 @@ contract Home is MerkleTreeManager, QueueManager, Common {
bytes32 _newRoot,
bytes memory _signature
) public notFailed returns (bool) {
require(Common.checkSig(_newRoot, _oldRoot, _signature), "bad sig");
require(_oldRoot == current, "Not a current update");
require(Common.checkSig(_oldRoot, _newRoot, _signature), "bad sig");
require(_oldRoot == current, "not a current update");
if (!queue.contains(_newRoot)) {
fail();
emit ImproperUpdate();

@ -79,7 +79,7 @@ library QueueLib {
view
returns (bool)
{
for (uint256 i = _q.first; i < _q.last; i++) {
for (uint256 i = _q.first; i <= _q.last; i++) {
if (_q.queue[i] == _item) {
return true;
}
@ -123,4 +123,12 @@ contract QueueManager {
constructor() {
queue.init();
}
function queueContains(bytes32 _item) external view returns (bool) {
return queue.contains(_item);
}
function queueEnd() external view returns (bytes32) {
return queue.lastItem();
}
}

@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
import "../Home.sol";
contract TestHome is Home {
using QueueLib for QueueLib.Queue;
using MerkleLib for MerkleLib.Tree;
constructor(uint32 _originSLIP44, address _sortition) Home(_originSLIP44, _sortition) {}
function setFailed() public {
_setFailed();
}
}

@ -9,7 +9,12 @@ contract TestQueue is QueueManager {
constructor() QueueManager() {}
// NB: this is unfortunately expensive
function contains(bytes32 _item) external view returns (bool) {
function contains(bytes32 _item)
external
view
returns (bool)
{
return queue.contains(_item);
}
@ -21,7 +26,10 @@ contract TestQueue is QueueManager {
return queue.peek();
}
function enqueue(bytes32 _item) external returns (uint256 _last) {
function enqueue(bytes32 _item)
external
returns (uint256 _last)
{
return queue.enqueue(_item);
}
@ -56,4 +64,4 @@ contract TestQueue is QueueManager {
function initAgain() external {
queue.init();
}
}
}

@ -35,7 +35,7 @@ extendEnvironment((hre) => {
this.address = address;
}
async static fromSigner(signer, originSlip44) {
static async fromSigner(signer, originSlip44) {
return new Updater(signer, await signer.getAddress(), originSlip44, true);
}
@ -52,11 +52,12 @@ extendEnvironment((hre) => {
async signUpdate(oldRoot, newRoot) {
let message = this.message(oldRoot, newRoot);
let signature = await this.signer.signMessage(message);
let msgHash = ethers.utils.arrayify(ethers.utils.keccak256(message));
let signature = await this.signer.signMessage(msgHash);
return {
origin: this.originSlip44,
newRoot,
oldRoot,
newRoot,
signature,
};
}

@ -187,9 +187,9 @@
}
},
"@ethersproject/basex": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.0.7.tgz",
"integrity": "sha512-OsXnRsujGmYD9LYyJlX+cVe5KfwgLUbUJrJMWdzRWogrygXd5HvGd7ygX1AYjlu1z8W/+t2FoQnczDR/H2iBjA==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.0.8.tgz",
"integrity": "sha512-PCVKZIShBQUqAXjJSvaCidThPvL0jaaQZcewJc0sf8Xx05BizaOS8r3jdPdpNdY+/qZtRDqwHTSKjvR/xssyLQ==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
@ -226,9 +226,9 @@
}
},
"@ethersproject/contracts": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.0.9.tgz",
"integrity": "sha512-CCTxVeDh6sjdSEbjzONhtwPjECvaHE62oGkY8M7kP0CHmgLD2SEGel0HZib8e5oQKRKGly9AKcUFW4g3rQ0AQw==",
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.0.10.tgz",
"integrity": "sha512-h9kdvllwT6B1LyUXeNQIb7Y6u6ZprP5LUiQIjSqvOehhm1sFZcaVtydsSa0LIg3SBC5QF0M7zH5p7EtI2VD0rQ==",
"dev": true,
"requires": {
"@ethersproject/abi": "^5.0.10",
@ -259,9 +259,9 @@
}
},
"@ethersproject/hdnode": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.0.8.tgz",
"integrity": "sha512-Mscpjd7BBjxYSWghaNMwV0xrBBkOoCq6YEPRm9MgE24CiBlzzbfEB5DGq6hiZqhQaxPkdCUtKKqZi3nt9hx43g==",
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.0.9.tgz",
"integrity": "sha512-S5UMmIC6XfFtqhUK4uTjD8GPNzSbE+sZ/0VMqFnA3zAJ+cEFZuEyhZDYnl2ItGJzjT4jsy+uEy1SIl3baYK1PQ==",
"dev": true,
"requires": {
"@ethersproject/abstract-signer": "^5.0.10",
@ -279,9 +279,9 @@
}
},
"@ethersproject/json-wallets": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.0.10.tgz",
"integrity": "sha512-Ux36u+d7Dm0M5AQ+mWuHdvfGPMN8K1aaLQgwzrsD4ELTWlwRuHuQbmn7/GqeOpbfaV6POLwdYcBk2TXjlGp/IQ==",
"version": "5.0.11",
"resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.0.11.tgz",
"integrity": "sha512-0GhWScWUlXXb4qJNp0wmkU95QS3YdN9UMOfMSEl76CRANWWrmyzxcBVSXSBu5iQ0/W8wO+xGlJJ3tpA6v3mbIw==",
"dev": true,
"requires": {
"@ethersproject/abstract-signer": "^5.0.10",
@ -325,9 +325,9 @@
}
},
"@ethersproject/pbkdf2": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.0.7.tgz",
"integrity": "sha512-0SNLNixPMqnosH6pyc4yPiUu/C9/Jbu+f6I8GJW9U2qNpMBddmRJviwseoha5Zw1V+Aw0Z/yvYyzIIE8yPXqLA==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.0.8.tgz",
"integrity": "sha512-UlmAMGbIPaS2xXsI38FbePVTfJMuU9jnwcqVn3p88HxPF4kD897ha+l3TNsBqJqf32UbQL5GImnf1oJkSKq4vQ==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
@ -344,9 +344,9 @@
}
},
"@ethersproject/providers": {
"version": "5.0.19",
"resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.0.19.tgz",
"integrity": "sha512-G+flo1jK1y/rvQy6b71+Nu7qOlkOKz+XqpgqFMZslkCzGuzQRmk9Qp7Ln4soK8RSyP1e5TCujaRf1H+EZahoaw==",
"version": "5.0.21",
"resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.0.21.tgz",
"integrity": "sha512-KyH9TylyLqspbO/2C0ph+0ZpOnb/2GkKQtpcs7IyHZ/wHXdhbClLeaBdO0b4Fpo6zAZWjgIdN6WUOMGkyy7b6A==",
"dev": true,
"requires": {
"@ethersproject/abstract-provider": "^5.0.8",
@ -371,9 +371,9 @@
}
},
"@ethersproject/random": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.0.7.tgz",
"integrity": "sha512-PxSRWwN3s+FH9AWMZU6AcWJsNQ9KzqKV6NgdeKPtxahdDjCuXxTAuzTZNXNRK+qj+Il351UnweAGd+VuZcOAlQ==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.0.8.tgz",
"integrity": "sha512-4rHtotmd9NjklW0eDvByicEkL+qareIyFSbG1ShC8tPJJSAC0g55oQWzw+3nfdRCgBHRuEE7S8EcPcTVPvZ9cA==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
@ -391,9 +391,9 @@
}
},
"@ethersproject/sha2": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.0.7.tgz",
"integrity": "sha512-MbUqz68hhp5RsaZdqi1eg1rrtiqt5wmhRYqdA7MX8swBkzW2KiLgK+Oh25UcWhUhdi1ImU9qrV6if5j0cC7Bxg==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.0.8.tgz",
"integrity": "sha512-ILP1ZgyvDj4rrdE+AXrTv9V88m7x87uga2VZ/FeULKPumOEw/4bGnJz/oQ8zDnDvVYRCJ+48VaQBS2CFLbk1ww==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
@ -426,9 +426,9 @@
}
},
"@ethersproject/solidity": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.0.8.tgz",
"integrity": "sha512-OJkyBq9KaoGsi8E8mYn6LX+vKyCURvxSp0yuGBcOqEFM3vkn9PsCiXsHdOXdNBvlHG5evJXwAYC2UR0TzgJeKA==",
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.0.9.tgz",
"integrity": "sha512-LIxSAYEQgLRXE3mRPCq39ou61kqP8fDrGqEeNcaNJS3aLbmAOS8MZp56uK++WsdI9hj8sNsFh78hrAa6zR9Jag==",
"dev": true,
"requires": {
"@ethersproject/bignumber": "^5.0.13",
@ -467,9 +467,9 @@
}
},
"@ethersproject/units": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.0.9.tgz",
"integrity": "sha512-4jIkcMVrJ3lCgXMO4M/2ww0/T/IN08vJTZld7FIAwa6aoBDTAy71+sby3sShl1SG3HEeKYbI3fBWauCUgPRUpQ==",
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.0.10.tgz",
"integrity": "sha512-eaiHi9ham5lbC7qpqxpae7OY/nHJUnRUnFFuEwi2VB5Nwe3Np468OAV+e+HR+jAK4fHXQE6PFBTxWGtnZuO37g==",
"dev": true,
"requires": {
"@ethersproject/bignumber": "^5.0.13",
@ -478,9 +478,9 @@
}
},
"@ethersproject/wallet": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.0.10.tgz",
"integrity": "sha512-5siYr38NhqZKH6DUr6u4PdhgOKur8Q6sw+JID2TitEUmW0tOl8f6rpxAe77tw6SJT60D2UcvgsyLtl32+Nl+ig==",
"version": "5.0.11",
"resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.0.11.tgz",
"integrity": "sha512-2Fg/DOvUltR7aZTOyWWlQhru+SKvq2UE3uEhXSyCFgMqDQNuc2nHXh1SHJtN65jsEbjVIppOe1Q7EQMvhmeeRw==",
"dev": true,
"requires": {
"@ethersproject/abstract-provider": "^5.0.8",
@ -514,9 +514,9 @@
}
},
"@ethersproject/wordlists": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.0.8.tgz",
"integrity": "sha512-px2mloc1wAcdTbzv0ZotTx+Uh/dfnDO22D9Rx8xr7+/PUwAhZQjoJ9t7Hn72nsaN83rWBXsLvFcIRZju4GIaEQ==",
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.0.9.tgz",
"integrity": "sha512-Sn6MTjZkfbriod6GG6+p43W09HOXT4gwcDVNj0YoPYlo4Zq2Fk6b1CU9KUX3c6aI17PrgYb4qwZm5BMuORyqyQ==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
@ -673,9 +673,9 @@
}
},
"@openzeppelin/contracts": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.3.0.tgz",
"integrity": "sha512-AemZEsQYtUp1WRkcmZm1div5ORfTpLquLaziCIrSagjxyKdmObxuaY1yjQ5SHFMctR8rLwp706NXTbiIRJg7pw==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.0.tgz",
"integrity": "sha512-qh+EiHWzfY/9CORr+eRUkeEUP1WiFUcq3974bLHwyYzLBUtK6HPaMkIUHi74S1rDTZ0sNz42DwPc5A4IJvN3rg==",
"dev": true
},
"@resolver-engine/core": {
@ -1877,15 +1877,6 @@
"type-detect": "^4.0.5"
}
},
"chai-as-promised": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
"integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
"dev": true,
"requires": {
"check-error": "^1.0.2"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@ -3388,47 +3379,79 @@
}
},
"ethers": {
"version": "5.0.26",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-5.0.26.tgz",
"integrity": "sha512-MqA8Fvutn3qEW0yBJOHeV6KZmRpF2rqlL2B5058AGkUFsuu6j5Ns/FRlMsbGeQwBz801IB23jQp7vjRfFsKSkg==",
"dev": true,
"requires": {
"@ethersproject/abi": "5.0.10",
"@ethersproject/abstract-provider": "5.0.8",
"@ethersproject/abstract-signer": "5.0.11",
"@ethersproject/address": "5.0.9",
"@ethersproject/base64": "5.0.7",
"@ethersproject/basex": "5.0.7",
"@ethersproject/bignumber": "5.0.13",
"@ethersproject/bytes": "5.0.9",
"@ethersproject/constants": "5.0.8",
"@ethersproject/contracts": "5.0.9",
"@ethersproject/hash": "5.0.10",
"@ethersproject/hdnode": "5.0.8",
"@ethersproject/json-wallets": "5.0.10",
"@ethersproject/keccak256": "5.0.7",
"@ethersproject/logger": "5.0.8",
"@ethersproject/networks": "5.0.7",
"@ethersproject/pbkdf2": "5.0.7",
"@ethersproject/properties": "5.0.7",
"@ethersproject/providers": "5.0.19",
"@ethersproject/random": "5.0.7",
"@ethersproject/rlp": "5.0.7",
"@ethersproject/sha2": "5.0.7",
"@ethersproject/signing-key": "5.0.8",
"@ethersproject/solidity": "5.0.8",
"@ethersproject/strings": "5.0.8",
"@ethersproject/transactions": "5.0.9",
"@ethersproject/units": "5.0.9",
"@ethersproject/wallet": "5.0.10",
"@ethersproject/web": "5.0.12",
"@ethersproject/wordlists": "5.0.8"
"version": "5.0.28",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-5.0.28.tgz",
"integrity": "sha512-prYYCmZMGbrhP2PEXA2re5BpNPjaCP2y5gO1dh1i+fPxdkldQOk+0c0l8KlnxwUztKq4E40xpB0gyURdcAOaAg==",
"dev": true,
"requires": {
"@ethersproject/abi": "5.0.11",
"@ethersproject/abstract-provider": "5.0.9",
"@ethersproject/abstract-signer": "5.0.12",
"@ethersproject/address": "5.0.10",
"@ethersproject/base64": "5.0.8",
"@ethersproject/basex": "5.0.8",
"@ethersproject/bignumber": "5.0.14",
"@ethersproject/bytes": "5.0.10",
"@ethersproject/constants": "5.0.9",
"@ethersproject/contracts": "5.0.10",
"@ethersproject/hash": "5.0.11",
"@ethersproject/hdnode": "5.0.9",
"@ethersproject/json-wallets": "5.0.11",
"@ethersproject/keccak256": "5.0.8",
"@ethersproject/logger": "5.0.9",
"@ethersproject/networks": "5.0.8",
"@ethersproject/pbkdf2": "5.0.8",
"@ethersproject/properties": "5.0.8",
"@ethersproject/providers": "5.0.21",
"@ethersproject/random": "5.0.8",
"@ethersproject/rlp": "5.0.8",
"@ethersproject/sha2": "5.0.8",
"@ethersproject/signing-key": "5.0.9",
"@ethersproject/solidity": "5.0.9",
"@ethersproject/strings": "5.0.9",
"@ethersproject/transactions": "5.0.10",
"@ethersproject/units": "5.0.10",
"@ethersproject/wallet": "5.0.11",
"@ethersproject/web": "5.0.13",
"@ethersproject/wordlists": "5.0.9"
},
"dependencies": {
"@ethersproject/abstract-signer": {
"@ethersproject/abi": {
"version": "5.0.11",
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.0.11.tgz",
"integrity": "sha512-RKOgPSEYafknA62SrD3OCK42AllHE4YBfKYXyQeM+sBP7Nq3X5FpzeoY4uzC43P4wIhmNoTHCKQuwnX7fBqb6Q==",
"resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.11.tgz",
"integrity": "sha512-ibZswQsjdFuLSfY2lbRTZM2Uk+ci7tp+mjVK0kjxVol2V32cb7va1r6B4AJU/Ac/VTstCjxtn0KKMfbkPc002w==",
"dev": true,
"requires": {
"@ethersproject/address": "^5.0.9",
"@ethersproject/bignumber": "^5.0.13",
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/constants": "^5.0.8",
"@ethersproject/hash": "^5.0.10",
"@ethersproject/keccak256": "^5.0.7",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/properties": "^5.0.7",
"@ethersproject/strings": "^5.0.8"
}
},
"@ethersproject/abstract-provider": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.0.9.tgz",
"integrity": "sha512-X9fMkqpeu9ayC3JyBkeeZhn35P4xQkpGX/l+FrxDtEW9tybf/UWXSMi8bGThpPtfJ6q6U2LDetXSpSwK4TfYQQ==",
"dev": true,
"requires": {
"@ethersproject/bignumber": "^5.0.13",
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/networks": "^5.0.7",
"@ethersproject/properties": "^5.0.7",
"@ethersproject/transactions": "^5.0.9",
"@ethersproject/web": "^5.0.12"
}
},
"@ethersproject/abstract-signer": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.0.12.tgz",
"integrity": "sha512-qt4jAEzQGPZ31My1gFGPzzJHJveYhVycW7RHkuX0W8fvMdg7wr0uvP7mQEptMVrb+jYwsVktCf6gBGwWDpFiTA==",
"dev": true,
"requires": {
"@ethersproject/abstract-provider": "^5.0.8",
@ -3437,6 +3460,170 @@
"@ethersproject/logger": "^5.0.8",
"@ethersproject/properties": "^5.0.7"
}
},
"@ethersproject/address": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.10.tgz",
"integrity": "sha512-70vqESmW5Srua1kMDIN6uVfdneZMaMyRYH4qPvkAXGkbicrCOsA9m01vIloA4wYiiF+HLEfL1ENKdn5jb9xiAw==",
"dev": true,
"requires": {
"@ethersproject/bignumber": "^5.0.13",
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/keccak256": "^5.0.7",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/rlp": "^5.0.7"
}
},
"@ethersproject/base64": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.0.8.tgz",
"integrity": "sha512-PNbpHOMgZpZ1skvQl119pV2YkCPXmZTxw+T92qX0z7zaMFPypXWTZBzim+hUceb//zx4DFjeGT4aSjZRTOYThg==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9"
}
},
"@ethersproject/bignumber": {
"version": "5.0.14",
"resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.14.tgz",
"integrity": "sha512-Q4TjMq9Gg3Xzj0aeJWqJgI3tdEiPiET7Y5OtNtjTAODZ2kp4y9jMNg97zVcvPedFvGROdpGDyCI77JDFodUzOw==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/logger": "^5.0.8",
"bn.js": "^4.4.0"
}
},
"@ethersproject/bytes": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.10.tgz",
"integrity": "sha512-vpu0v1LZ1j1s9kERQIMnVU69MyHEzUff7nqK9XuCU4vx+AM8n9lU2gj7jtJIvGSt9HzatK/6I6bWusI5nyuaTA==",
"dev": true,
"requires": {
"@ethersproject/logger": "^5.0.8"
}
},
"@ethersproject/constants": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.9.tgz",
"integrity": "sha512-2uAKH89UcaJP/Sc+54u92BtJtZ4cPgcS1p0YbB1L3tlkavwNvth+kNCUplIB1Becqs7BOZr0B/3dMNjhJDy4Dg==",
"dev": true,
"requires": {
"@ethersproject/bignumber": "^5.0.13"
}
},
"@ethersproject/hash": {
"version": "5.0.11",
"resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.11.tgz",
"integrity": "sha512-H3KJ9fk33XWJ2djAW03IL7fg3DsDMYjO1XijiUb1hJ85vYfhvxu0OmsU7d3tg2Uv1H1kFSo8ghr3WFQ8c+NL3g==",
"dev": true,
"requires": {
"@ethersproject/abstract-signer": "^5.0.10",
"@ethersproject/address": "^5.0.9",
"@ethersproject/bignumber": "^5.0.13",
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/keccak256": "^5.0.7",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/properties": "^5.0.7",
"@ethersproject/strings": "^5.0.8"
}
},
"@ethersproject/keccak256": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.8.tgz",
"integrity": "sha512-zoGbwXcWWs9MX4NOAZ7N0hhgIRl4Q/IO/u9c/RHRY4WqDy3Ywm0OLamEV53QDwhjwn3YiiVwU1Ve5j7yJ0a/KQ==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
"js-sha3": "0.5.7"
}
},
"@ethersproject/logger": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.9.tgz",
"integrity": "sha512-kV3Uamv3XOH99Xf3kpIG3ZkS7mBNYcLDM00JSDtNgNB4BihuyxpQzIZPRIDmRi+95Z/R1Bb0X2kUNHa/kJoVrw==",
"dev": true
},
"@ethersproject/networks": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.0.8.tgz",
"integrity": "sha512-PYpptlO2Tu5f/JEBI5hdlMds5k1DY1QwVbh3LKPb3un9dQA2bC51vd2/gRWAgSBpF3kkmZOj4FhD7ATLX4H+DA==",
"dev": true,
"requires": {
"@ethersproject/logger": "^5.0.8"
}
},
"@ethersproject/properties": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.8.tgz",
"integrity": "sha512-zEnLMze2Eu2VDPj/05QwCwMKHh506gpT9PP9KPVd4dDB+5d6AcROUYVLoIIQgBYK7X/Gw0UJmG3oVtnxOQafAw==",
"dev": true,
"requires": {
"@ethersproject/logger": "^5.0.8"
}
},
"@ethersproject/rlp": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.8.tgz",
"integrity": "sha512-E4wdFs8xRNJfzNHmnkC8w5fPeT4Wd1U2cust3YeT16/46iSkLT8nn8ilidC6KhR7hfuSZE4UqSPzyk76p7cdZg==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/logger": "^5.0.8"
}
},
"@ethersproject/signing-key": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.9.tgz",
"integrity": "sha512-AobnsEiLv+Z4a/NbbelwB/Lsnc+qxeNejXDlEwbo/nwjijvxLpwiNN+rjx/lQGel1QnQ/d+lEv7xezyUaXdKFQ==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/properties": "^5.0.7",
"elliptic": "6.5.3"
}
},
"@ethersproject/strings": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.9.tgz",
"integrity": "sha512-ogxBpcUpdO524CYs841MoJHgHxEPUy0bJFDS4Ezg8My+WYVMfVAOlZSLss0Rurbeeam8CpUVDzM4zUn09SU66Q==",
"dev": true,
"requires": {
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/constants": "^5.0.8",
"@ethersproject/logger": "^5.0.8"
}
},
"@ethersproject/transactions": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.10.tgz",
"integrity": "sha512-Tqpp+vKYQyQdJQQk4M73tDzO7ODf2D42/sJOcKlDAAbdSni13v6a+31hUdo02qYXhVYwIs+ZjHnO4zKv5BNk8w==",
"dev": true,
"requires": {
"@ethersproject/address": "^5.0.9",
"@ethersproject/bignumber": "^5.0.13",
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/constants": "^5.0.8",
"@ethersproject/keccak256": "^5.0.7",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/properties": "^5.0.7",
"@ethersproject/rlp": "^5.0.7",
"@ethersproject/signing-key": "^5.0.8"
}
},
"@ethersproject/web": {
"version": "5.0.13",
"resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.0.13.tgz",
"integrity": "sha512-G3x/Ns7pQm21ALnWLbdBI5XkW/jrsbXXffI9hKNPHqf59mTxHYtlNiSwxdoTSwCef3Hn7uvGZpaSgTyxs7IufQ==",
"dev": true,
"requires": {
"@ethersproject/base64": "^5.0.7",
"@ethersproject/bytes": "^5.0.9",
"@ethersproject/logger": "^5.0.8",
"@ethersproject/properties": "^5.0.7",
"@ethersproject/strings": "^5.0.8"
}
}
}
},
@ -10072,6 +10259,16 @@
"verror": "1.10.0"
}
},
"keccak": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz",
"integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==",
"dev": true,
"requires": {
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
}
},
"keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",

@ -3,11 +3,11 @@
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.1",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@openzeppelin/contracts": "^3.3.0",
"@openzeppelin/contracts": "^3.4.0",
"@summa-tx/memview-sol": "^1.1.1",
"chai": "^4.2.0",
"ethereum-waffle": "^3.2.2",
"ethers": "^5.0.26",
"ethers": "^5.0.28",
"hardhat": "^2.0.8",
"hardhat-gas-reporter": "^1.0.4",
"prettier": "2.2.1",
@ -22,7 +22,7 @@
},
"dependencies": {},
"scripts": {
"prettier": "prettier --write 'contracts/**/*.sol' ./test ./scripts ./lib",
"prettier": "prettier --write 'contracts/**/*.sol' ./test ./scripts",
"compile": "hardhat compile && ./scripts/update_abis.sh",
"coverage": "hardhat coverage",
"test": "hardhat test"

@ -0,0 +1,132 @@
const { waffle, ethers } = require('hardhat');
const { provider, deployMockContract } = waffle;
const { expect } = require('chai');
const NoSortition = require('../artifacts/contracts/Sortition.sol/NoSortition.json');
const ACTIVE = 0;
const FAILED = 1;
const originSLIP44 = 1234;
describe('Home', async () => {
let home, signer, fakeSigner, updater, fakeUpdater;
// Helper function that enqueues message and returns its root
const enqueueMessageAndGetRoot = async (message, recipient) => {
message = ethers.utils.formatBytes32String(message);
recipient = ethers.utils.formatBytes32String(recipient);
await home.enqueue(originSLIP44, recipient, message);
const [_currentRoot, latestRoot] = await home.suggestUpdate();
return latestRoot;
};
before(async () => {
[signer, fakeSigner] = provider.getWallets();
updater = await optics.Updater.fromSigner(signer, originSLIP44);
fakeUpdater = await optics.Updater.fromSigner(fakeSigner, originSLIP44);
});
beforeEach(async () => {
const mockSortition = await deployMockContract(signer, NoSortition.abi);
await mockSortition.mock.current.returns(signer.address);
await mockSortition.mock.slash.returns();
const Home = await ethers.getContractFactory('TestHome');
home = await Home.deploy(originSLIP44, mockSortition.address);
await home.deployed();
});
it('Halts on fail', async () => {
await home.setFailed();
expect(await home.state()).to.equal(FAILED);
const recipient = ethers.utils.formatBytes32String('recipient');
const message = ethers.utils.formatBytes32String('message');
await expect(
home.enqueue(originSLIP44, recipient, message),
).to.be.revertedWith('failed state');
});
it('Suggests current root and latest root on suggestUpdate', async () => {
const currentRoot = await home.current();
const recipient = ethers.utils.formatBytes32String('recipient');
const message = ethers.utils.formatBytes32String('message');
await home.enqueue(originSLIP44, recipient, message);
const latestEnqueuedRoot = await home.queueEnd();
const [suggestedCurrent, suggestedNew] = await home.suggestUpdate();
expect(suggestedCurrent).to.equal(currentRoot);
expect(suggestedNew).to.equal(latestEnqueuedRoot);
});
it('Accepts a valid update', async () => {
const currentRoot = await home.current();
const newRoot = await enqueueMessageAndGetRoot('message', 'recipient');
const { signature } = await updater.signUpdate(currentRoot, newRoot);
await expect(home.update(currentRoot, newRoot, signature))
.to.emit(home, 'Update')
.withArgs(originSLIP44, currentRoot, newRoot, signature);
});
it('Rejects update that does not build off of current root', async () => {
// First root is current root
const secondRoot = await enqueueMessageAndGetRoot('message', 'recipient');
const thirdRoot = await enqueueMessageAndGetRoot('message2', 'recipient2');
// Try to submit update that skips the current (first) root
const { signature } = await updater.signUpdate(secondRoot, thirdRoot);
await expect(
home.update(secondRoot, thirdRoot, signature),
).to.be.revertedWith('not a current update');
});
it('Rejects update that does not exist in queue', async () => {
const currentRoot = await home.current();
const fakeNewRoot = ethers.utils.formatBytes32String('fake root');
const { signature } = await updater.signUpdate(currentRoot, fakeNewRoot);
await expect(home.update(currentRoot, fakeNewRoot, signature)).to.emit(
home,
'ImproperUpdate',
);
expect(await home.state()).to.equal(FAILED);
});
it('Rejects update from non-updater address', async () => {
const currentRoot = await home.current();
const newRoot = await enqueueMessageAndGetRoot('message', 'recipient');
const { signature: fakeSignature } = await fakeUpdater.signUpdate(
currentRoot,
newRoot,
);
await expect(
home.update(currentRoot, newRoot, fakeSignature),
).to.be.revertedWith('bad sig');
});
it('Fails on valid double update proof', async () => {
const firstRoot = await home.current();
const secondRoot = await enqueueMessageAndGetRoot('message', 'recipient');
const thirdRoot = await enqueueMessageAndGetRoot('message2', 'recipient2');
const { signature } = await updater.signUpdate(firstRoot, secondRoot);
const { signature: signature2 } = await updater.signUpdate(
firstRoot,
thirdRoot,
);
await expect(
home.doubleUpdate(
firstRoot,
[secondRoot, thirdRoot],
signature,
signature2,
),
).to.emit(home, 'DoubleUpdate');
expect(await home.state()).to.equal(FAILED);
});
});
Loading…
Cancel
Save