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)
- should perform the same as
- [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
- 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