This bounty is no longer available
Web3 DAO | gooddollar Logo

EVM Storage proofs Fuse.io generic bridge - 4K$ worth of G$+Fuse tokens

Organization

gooddollar

Deadline

in over 262 years

Status

ENDED

4000 USD

INSTRUCTIONS

Motivation

The GoodDollar protocol needs a secure and robust bridge to the Fuse network, for scaling TXs and also Voting. Also having a generic evm bridge would make supporting other EVM based blockchains easier.

To get approved you must read the link below and contact us on our telegram channel

To get started please read about our bounty mentorship program here: https://github.com/GoodDollar/Bounties/

Details

See proposal on Fuse forum for more context:

Part 1 - Block headers registry contract - 1000$

The purpose of the contract is to store on Fuse, block headers from different blockchains signed by the Fuse validators.

  • [x] Most write methods to this contract should be limited to current validators
  • [x] The contract should hold validator signatures per blockhash (ie mapping blockhash -> SignedBlock)
  • [x] The contract should hold mapping from blockchain+block_number -> array<blockhashes>
SignedBlock {
 signatures:bytes[],
 cycleEnd: uint256, //just for fuse
validators: address[],//just for fuse
 hasValidatorSigned: mapping<address> -> bool, //to prevent double signatures
}
  • [ ] the contract will hold a mapping of blockhash -> BlockHeader
Header {
  parent_hash: bytes32
  timestamp: uint256,
  number: uint256,
  author: address,
  transactions_root: bytes32,
  uncles_hash: bytes32,
  extra_data: bytes,
  state_root: bytes32,
  receipts_root: bytes32,
  log_bloom: bytes,
  gas_used: uint256,
  gas_limit: uint256,
  difficulty: uint256,
  mixHash:bytes32,
 nonce:uint256
}
Block {
 header: BlockHeader,
 rlpHeader: bytes,
 signature: bytes,
 blockchainId: uint256,
 blockHash: bytes32,
 validators: address[],
 cycleEnd: uint256
}
  • [x] internal method _addSignedBlock(blockchainid,blockheader,blockhash,signature)
    • if blockhash doesnt exists yet, verify hash(blockheader) = blockhash and store header
    • verify signature is of the blockhash and by the msg.sender validator
    • verify validator didnt already submit this block (probably need another mapping for that)
    • add the validator signature for that specific blockhash
    • add blockhash to (blockchain+blocknumber) -> blockhashes mapping
  • [x] view getSignedBlock(blockchain,block number):(rlpHeader, Array<signatures>, Array<validators>, cycleEnd) - returns the data for the block with most signatures
  • [x] internal method `_addFuseSignedBlock(blockheader,blockhash,validators,cycleend,signature)
    • should perform the same as addSignedBlock just with added logic
    • key for blockhash mapping is defined as hash(blockhash,validators,cycleEnd)
    • signature is also expected to match digest of hash(blockhash,validators,cycleEnd)
  • [x] method addSignedBlocks(Block[] blocks) - the main entry to bulk add blocks
  • [x] method addBlockchain(blockchainId, rpc: string) onlyvoting - keeps a list of blockchains that validators should read blocks from
  • [ ] unit tests

Part 2 - Extend Fuse validators' nodejs app - 1500$

  • [ ] read list of extra blockchains + RPCs from registry contract. By default fuse+ethereum+bsc are always enabled no matter if they are in the list or not
  • [x] create provider connections and listen to new blocks (for example etherjs provider.on("block") - https://docs.ethers.io/v5/api/providers/provider/#Provider--event-methods)
  • [x] on each incoming sign the blockhash and push block data (see data type Block) to an array
    • for fuse read from consensus the cycleEnd value and the current validators value
    • notice that for fuse sealFields is instead of mixhash/digest and nonce
    • notice that for different blockchains the author/mixdigest fields can be named differently, coinbase,miner etc..
  • [x] set timer for every X seconds to publish the signed blocks
    • clone the blocks array
    • reset the original array
    • call addSignedBlocks
  • [ ] error handling
    • listen to provider errors and try to reconnect
    • catch fuse read/write tx errors and add a retry (ie something like the package @jsier/retrier
  • [ ] unit tests

Part 3 - Custom Bridge POC - 1500$

Create a smart contract that is able to verify a new Fuse signed block data and also that is able to verify some other block was signed by X validators in the past using storage proofs on latest block

  • [ ] initialize - initialize the contract with a given set of validators
  • [ ] method to set the latest Fuse block. setLatestBlock(BlockHeader,validators,cycleEnd, signatures)
    • require that block number > last blocknumber
    • require signatures are:
      • of digest (blockhash,validators,cycleEnd)
      • signed by validator in existing validator set
      • 66% validators in set

    • if blocknumber > stored cycleEnd then update the validator set
    • store latest block, cycleEnd
  • [ ] method to prove a past block was signed by X validators. provePastBlock(blockhash, validators, cycleEnd, storageProof)
    • use storage proofs to prove that last block submited contains in the SignedBlock mapping an entry for hash(blockhash,validators,cycleEnd) and that this entry signatures field length >= 66% validators
    • https://docs.soliditylang.org/en/v0.6.6/miscellaneous.html#layout-of-state-variables-in-storage
    • https://github.com/aragon/evm-storage-proofs
    • https://github.com/lidofinance/curve-merkle-oracle/blob/main/contracts/StableSwapStateOracle.sol
    • https://github.com/zmitton/eth-proof
    • https://github.com/KyberNetwork/peace-relay
    • https://github.com/PISAresearch/event-proofs