diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e2e84b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +node_modules/ diff --git a/truffle/contracts/IVerifier.sol b/truffle/contracts/IVerifier.sol new file mode 100644 index 0000000..c524943 --- /dev/null +++ b/truffle/contracts/IVerifier.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.5.4; +pragma experimental ABIEncoderV2; + +import "./Structs.sol"; + +contract IVerifier is Structs { + function isValid(Data calldata data, Proof calldata proof) external returns (bool); +} diff --git a/truffle/contracts/Lazy.sol b/truffle/contracts/Lazy.sol new file mode 100644 index 0000000..404b215 --- /dev/null +++ b/truffle/contracts/Lazy.sol @@ -0,0 +1,83 @@ +pragma solidity ^0.5.4; +pragma experimental ABIEncoderV2; + +import "./IVerifier.sol"; +import "./Structs.sol"; + +contract Lazy is Structs { + event Submitted(address indexed sender, uint256 index, Task task); + event Challenged(address indexed challenger, uint256 index); + + + enum Status {UNCHECKED, VALID, INVALID, FINALIZED} + struct Task { + Data data; + Proof proof; + address payable submitter; + uint timestamp; + Status status; + } + + Task[] public tasks; + + uint256 public stake; + IVerifier public verifier; + + /// @dev This function submits data. + /// @param data - public inptut for zkp + /// @param proof - proof that verifies input + function submit(Data calldata data, Proof calldata proof) external payable { + require(msg.value == stake); + + Task memory task = Task(data, proof, msg.sender, uint96(now), Status.UNCHECKED); + uint index = tasks.push(task); + + emit Submitted(msg.sender, index, task); + } + + /// @dev This function challenges a submission by calling the validation function. + /// @param id The id of the submission to challenge. + function challenge(uint id) external { + Task storage task = tasks[id]; + require(now < task.timestamp + 1 weeks); + require(task.status == Status.UNCHECKED); + + if (verifier.isValid(task.data, task.proof)) { + task.status = Status.VALID; + task.submitter.transfer(stake); + } else { + task.status = Status.INVALID; + msg.sender.transfer(stake); + } + + + // пруф не подходит, на это надо реагировать + + emit Challenged(msg.sender, id); + } + + function finzalize(uint id) external { + Task storage task = tasks[id]; + require(now > task.timestamp + 1 weeks); + require(task.status == Status.UNCHECKED); + + task.status = Status.FINALIZED; + msg.sender.transfer(stake); + } + + + + function last5Timestamps() view external returns (uint256[5] memory result) { + uint256 length = tasks.length; + for (uint256 i = 1; i <= 5; i++) { + result[i - 1] = tasks[length - i].timestamp; + } + + return result; + } + + function getDataById(uint256 id) view external returns (Task memory task) { + task = tasks[tasks.length - 1 - id]; + } +} + diff --git a/truffle/contracts/Migrations.sol b/truffle/contracts/Migrations.sol new file mode 100644 index 0000000..c378ffb --- /dev/null +++ b/truffle/contracts/Migrations.sol @@ -0,0 +1,23 @@ +pragma solidity >=0.4.21 <0.6.0; + +contract Migrations { + address public owner; + uint public last_completed_migration; + + constructor() public { + owner = msg.sender; + } + + modifier restricted() { + if (msg.sender == owner) _; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } + + function upgrade(address new_address) public restricted { + Migrations upgraded = Migrations(new_address); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/truffle/contracts/Structs.sol b/truffle/contracts/Structs.sol new file mode 100644 index 0000000..67a3d86 --- /dev/null +++ b/truffle/contracts/Structs.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.5.4; + +interface Structs { + struct Data { + uint x; + } + + struct Proof { + uint x; + } + +} diff --git a/truffle/migrations/1_initial_migration.js b/truffle/migrations/1_initial_migration.js new file mode 100644 index 0000000..ee2135d --- /dev/null +++ b/truffle/migrations/1_initial_migration.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("Migrations"); + +module.exports = function(deployer) { + deployer.deploy(Migrations); +}; diff --git a/truffle/migrations/2_deploy_lazy.js b/truffle/migrations/2_deploy_lazy.js new file mode 100644 index 0000000..d33a75b --- /dev/null +++ b/truffle/migrations/2_deploy_lazy.js @@ -0,0 +1,5 @@ +var Lazy = artifacts.require('Lazy'); + +module.exports = function(deployer) { + deployer.deploy(Lazy); +} \ No newline at end of file diff --git a/truffle/package.json b/truffle/package.json new file mode 100644 index 0000000..4a5d1bd --- /dev/null +++ b/truffle/package.json @@ -0,0 +1,23 @@ +{ + "name": "testsuite-contract", + "version": "1.0.0", + "description": "", + "main": "truffle-config.js", + "directories": { + "test": "test" + }, + "dependencies": { + "babel-polyfill": "^6.26.0", + "babel-register": "^6.26.0", + "ganache-cli": "^6.4.1", + "openzeppelin-solidity": "^2.1.3", + "truffle": "5.0.8", + "truffle-hdwallet-provider": "1.0.5" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/truffle/truffle.js b/truffle/truffle.js new file mode 100644 index 0000000..c3f69bb --- /dev/null +++ b/truffle/truffle.js @@ -0,0 +1,59 @@ +/*require('babel-register'); +require('babel-polyfill'); +*/ +var HDWalletProvider = require("truffle-hdwallet-provider"); + +var mnemonicRopsten = "..."; +var infuraLinkRopsten = "..."; +var deployerAddressRopsten = "..."; + +var mnemonicKovan = "..."; +var infuraLinkKovan = "..."; +var deployerAddressKovan = "..."; +var addressIndex = 0; // address index in MetaMask + + +module.exports = { + networks: { + development: { + host: "localhost", + network_id: "*", + port: 8545, + }, + coverage: { + host: "localhost", + network_id: "*", + port: 8555, // <-- If you change this, also set the port option in .solcover.js. + gas: 0xfffffffffff, // <-- Use this high gas value + gasPrice: 0x01 // <-- Use this low gas price + }, + ropsten: { + provider: function() { + return new HDWalletProvider(mnemonicRopsten, infuraLinkRopsten, addressIndex); + }, + network_id: 3, + from: deployerAddressRopsten.toLowerCase(), + }, + kovan: { + provider: function() { + return new HDWalletProvider(mnemonicKovan, infuraLinkKovan, addressIndex); + }, + network_id: 42, + from: deployerAddressKovan.toLowerCase(), + } + + }, + compilers: { + solc: { + version: "0.5.4", + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + } + } + // See + // to customize your Truffle configuration! +};