From 1f22e023eba871f07db7bccfe4ce51f95b18cc4b Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Mon, 8 Feb 2021 14:13:22 -0800 Subject: [PATCH] test: adds tests for Common contract (fixed history) (#57) * test: adds output function to print hashes used in solidity/test/domainHashTestCases.json * test: adds domainHashTestCases.json file * test: adds signature and domainHash calculation tests to common tests * fix: runs prettier on contracts --- rust/optics-core/Cargo.toml | 1 - rust/optics-core/src/utils.rs | 13 +++++ solidity/contracts/test/TestCommon.sol | 32 +++++++++++ solidity/test/Common.test.js | 77 ++++++++++++++++++++++++++ solidity/test/domainHashTestCases.json | 16 ++++++ 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 solidity/contracts/test/TestCommon.sol create mode 100644 solidity/test/Common.test.js create mode 100644 solidity/test/domainHashTestCases.json diff --git a/rust/optics-core/Cargo.toml b/rust/optics-core/Cargo.toml index 16aa4a358..fae03705f 100644 --- a/rust/optics-core/Cargo.toml +++ b/rust/optics-core/Cargo.toml @@ -17,7 +17,6 @@ tracing-futures = "0.2.4" serde = {version = "1.0", features = ["derive"]} serde_json = {version = "1.0"} - [dev-dependencies] tokio = {version = "1.0.1", features = ["rt", "time"]} diff --git a/rust/optics-core/src/utils.rs b/rust/optics-core/src/utils.rs index 16984e3bb..1042bffdb 100644 --- a/rust/optics-core/src/utils.rs +++ b/rust/optics-core/src/utils.rs @@ -10,3 +10,16 @@ pub(crate) fn domain_hash(origin_slip44_id: u32) -> H256 { .as_slice(), ) } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + // Prints domain hashes used in solidity/test/domainHashTestCases.sol + fn output_domain_hashes() { + for n in 1..=3 { + println!("Domain hash for originSlip44 of {}: {:?}", n, domain_hash(n)); + } + } +} \ No newline at end of file diff --git a/solidity/contracts/test/TestCommon.sol b/solidity/contracts/test/TestCommon.sol new file mode 100644 index 000000000..7175e4c90 --- /dev/null +++ b/solidity/contracts/test/TestCommon.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity >=0.6.11; + +import "../Common.sol"; + +contract TestCommon is Common { + constructor( + uint32 _originSLIP44, + address _updater, + bytes32 _current + ) Common(_originSLIP44, _updater, _current) {} + + function testCheckSig( + bytes32 _oldRoot, + bytes32 _newRoot, + bytes memory _signature + ) external view returns (bool) { + return checkSig(_oldRoot, _newRoot, _signature); + } + + function fail() internal override { + _setFailed(); + } + + function testDomainHash(uint32 _originSLIP44) + external + pure + returns (bytes32) + { + return keccak256(abi.encodePacked(_originSLIP44, "OPTICS")); + } +} diff --git a/solidity/test/Common.test.js b/solidity/test/Common.test.js new file mode 100644 index 000000000..3912ece39 --- /dev/null +++ b/solidity/test/Common.test.js @@ -0,0 +1,77 @@ +const { waffle, ethers } = require('hardhat'); +const { provider, deployMockContract } = waffle; +const { expect } = require('chai'); + +const { testCases } = require('./domainHashTestCases.json'); + +const ACTIVE = 0; +const FAILED = 1; +const originSLIP44 = 1234; + +describe('Common', async () => { + let common, signer, fakeSigner, updater, fakeUpdater, initialRoot; + + before(async () => { + [signer, fakeSigner] = provider.getWallets(); + updater = await optics.Updater.fromSigner(signer, originSLIP44); + fakeUpdater = await optics.Updater.fromSigner(fakeSigner, originSLIP44); + initialRoot = ethers.utils.formatBytes32String('initial root'); + }); + + beforeEach(async () => { + const CommonFactory = await ethers.getContractFactory('TestCommon'); + common = await CommonFactory.deploy( + originSLIP44, + updater.signer.address, + initialRoot, + ); + await common.deployed(); + }); + + it('Accepts updater signature', async () => { + const oldRoot = ethers.utils.formatBytes32String('old root'); + const newRoot = ethers.utils.formatBytes32String('new root'); + + const { signature } = await updater.signUpdate(oldRoot, newRoot); + expect(await common.testCheckSig(oldRoot, newRoot, signature)).to.be.true; + }); + + it('Rejects non-updater signature', async () => { + const oldRoot = ethers.utils.formatBytes32String('old root'); + const newRoot = ethers.utils.formatBytes32String('new root'); + + const { signature: fakeSignature } = await fakeUpdater.signUpdate( + oldRoot, + newRoot, + ); + expect(await common.testCheckSig(oldRoot, newRoot, fakeSignature)).to.be + .false; + }); + + it('Fails on valid double update proof', async () => { + const oldRoot = ethers.utils.formatBytes32String('old root'); + const newRoot = ethers.utils.formatBytes32String('new root 1'); + const newRoot2 = ethers.utils.formatBytes32String('new root 2'); + + const { signature } = await updater.signUpdate(oldRoot, newRoot); + const { signature: signature2 } = await updater.signUpdate( + oldRoot, + newRoot2, + ); + + await expect( + common.doubleUpdate(oldRoot, [newRoot, newRoot2], signature, signature2), + ).to.emit(common, 'DoubleUpdate'); + + expect(await common.state()).to.equal(FAILED); + }); + + it('Calculates domain hashes from originSLIP44', async () => { + // Compare Rust output in json file to solidity output + for (let testCase of testCases) { + const { originSlip44, expectedDomainHash } = testCase; + const solidityDomainHash = await common.testDomainHash(originSlip44); + expect(solidityDomainHash).to.equal(expectedDomainHash); + } + }); +}); diff --git a/solidity/test/domainHashTestCases.json b/solidity/test/domainHashTestCases.json new file mode 100644 index 000000000..72765a1fc --- /dev/null +++ b/solidity/test/domainHashTestCases.json @@ -0,0 +1,16 @@ +{ + "testCases": [ + { + "originSlip44": 1, + "expectedDomainHash": "0xfa923b9e3942a539792474b49136600ed6690d0e51c6993e9238819047dfea63" + }, + { + "originSlip44": 2, + "expectedDomainHash": "0x8caa11ba0b38c460170899d835c99eb38b9319603fe5d391c469da2657e01039" + }, + { + "originSlip44": 3, + "expectedDomainHash": "0xa2718888038cf3886089211e47a6f2fb003fc887a4f748fd6278156f23f9ecbf" + } + ] +}