From 85135e0e8e2eee3de3c04d9e497d7d16678189c5 Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Fri, 16 Jun 2023 19:37:17 +0300 Subject: [PATCH] feat(relay): Make relayer work with new version of hashi adapter --- .../src/truth/eth/BeaconLightClient.sol | 2 +- .../solidity/tasks/hashi_abi.json | 85 +++++++++++++++++++ .../publish_evm_transaction.ts | 33 +++++++ relay/implementations/solidity-contract.ts | 23 +---- relay/on_chain_publisher.ts | 26 ++++-- 5 files changed, 138 insertions(+), 31 deletions(-) diff --git a/beacon-light-client/solidity/contracts/bridge/src/truth/eth/BeaconLightClient.sol b/beacon-light-client/solidity/contracts/bridge/src/truth/eth/BeaconLightClient.sol index 84493c31f..144d01b52 100644 --- a/beacon-light-client/solidity/contracts/bridge/src/truth/eth/BeaconLightClient.sol +++ b/beacon-light-client/solidity/contracts/bridge/src/truth/eth/BeaconLightClient.sol @@ -61,7 +61,7 @@ contract BeaconLightClient is LightClientUpdateVerifier, ILightClient { return executionStateRoots[currentIndex]; } - // TODO: fix + // TODO: fix name to lightClientUpdate function light_client_update(LightClientUpdate calldata update) external payable diff --git a/beacon-light-client/solidity/tasks/hashi_abi.json b/beacon-light-client/solidity/tasks/hashi_abi.json index 001394d2a..8a656e613 100644 --- a/beacon-light-client/solidity/tasks/hashi_abi.json +++ b/beacon-light-client/solidity/tasks/hashi_abi.json @@ -68,6 +68,11 @@ "name": "InvalidBlockNumberProof", "type": "error" }, + { + "inputs": [], + "name": "InvalidUpdate", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -203,5 +208,85 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_chainId", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "_slot", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "_blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "_blockNumberProof", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "_blockHash", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "_blockHashProof", + "type": "bytes32[]" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "attestedHeaderRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "attestedHeaderSlot", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "finalizedHeaderRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "finalizedExecutionStateRoot", + "type": "bytes32" + }, + { + "internalType": "uint256[2]", + "name": "a", + "type": "uint256[2]" + }, + { + "internalType": "uint256[2][2]", + "name": "b", + "type": "uint256[2][2]" + }, + { + "internalType": "uint256[2]", + "name": "c", + "type": "uint256[2]" + } + ], + "internalType": "struct LightClientUpdate", + "name": "update", + "type": "tuple" + } + ], + "name": "storeBlockHeader", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ] diff --git a/relay/implementations/publish_evm_transaction.ts b/relay/implementations/publish_evm_transaction.ts index 677fc0f08..08a7222bc 100644 --- a/relay/implementations/publish_evm_transaction.ts +++ b/relay/implementations/publish_evm_transaction.ts @@ -1,6 +1,7 @@ import { BigNumber, Contract } from 'ethers'; import Web3 from 'web3'; import { FeeHistoryResult } from 'web3-eth'; +import { groth16 } from 'snarkjs'; type Block = { number: number | string; @@ -104,6 +105,38 @@ export async function publishTransaction( } } +export async function getSolidityProof(update: { + a: string[]; + b: string[][]; + c: string[]; +}): Promise<{ + a: string[]; + b: string[][]; + c: string[]; +}> { + const calldata = await groth16.exportSolidityCallData( + { + pi_a: update.a, + pi_b: update.b, + pi_c: update.c, + }, + [], + ); + + const argv: string[] = calldata + .replace(/["[\]\s]/g, '') + .split(',') + .map(x => BigInt(x).toString()); + + const a = [argv[0], argv[1]]; + const b = [ + [argv[2], argv[3]], + [argv[4], argv[5]], + ]; + const c = [argv[6], argv[7]]; + return { a, b, c }; +} + async function getGasPrice(web3: Web3, transactionSpeed: TransactionSpeed) { const formattedBlocks = formatFeeHistory( await web3.eth.getFeeHistory(historicalBlocks, 'pending', [1, 50, 99]), diff --git a/relay/implementations/solidity-contract.ts b/relay/implementations/solidity-contract.ts index f3d2cbb0b..9f36d5193 100644 --- a/relay/implementations/solidity-contract.ts +++ b/relay/implementations/solidity-contract.ts @@ -1,9 +1,9 @@ import { Contract } from 'ethers'; import { ISmartContract } from '../abstraction/smart-contract-abstraction'; -import { groth16 } from 'snarkjs'; import Web3 from 'web3'; import { TransactionSpeed, + getSolidityProof, publishTransaction, } from './publish_evm_transaction'; @@ -35,26 +35,7 @@ export class SolidityContract implements ISmartContract { b: string[][]; c: string[]; }): Promise { - const calldata = await groth16.exportSolidityCallData( - { - pi_a: update.a, - pi_b: update.b, - pi_c: update.c, - }, - [], - ); - - const argv: string[] = calldata - .replace(/["[\]\s]/g, '') - .split(',') - .map(x => BigInt(x).toString()); - - const a = [argv[0], argv[1]]; - const b = [ - [argv[2], argv[3]], - [argv[4], argv[5]], - ]; - const c = [argv[6], argv[7]]; + const { a, b, c } = await getSolidityProof(update); await publishTransaction( this.lightClientContract, diff --git a/relay/on_chain_publisher.ts b/relay/on_chain_publisher.ts index 51da1b115..32e95d449 100644 --- a/relay/on_chain_publisher.ts +++ b/relay/on_chain_publisher.ts @@ -5,6 +5,7 @@ import { ISmartContract } from './abstraction/smart-contract-abstraction'; import { Contract } from 'ethers'; import { TransactionSpeed, + getSolidityProof, publishTransaction, } from './implementations/publish_evm_transaction'; import Web3 from 'web3'; @@ -141,21 +142,20 @@ export async function postUpdateOnChain( console.log(update); - await lightClientContract.postUpdateOnChain({ - ...update, - a: proofResult.proof.pi_a, - b: proofResult.proof.pi_b, - c: proofResult.proof.pi_c, - }); - if (hashiAdapterContract) { const hashiInfo = await beaconApi.getHashiAdapterInfo( proofResult.proofInput.nextHeaderSlot, ); + const solidityProof = await getSolidityProof({ + a: proofResult.proof.pi_a, + b: proofResult.proof.pi_b, + c: proofResult.proof.pi_c, + }); + await publishTransaction( hashiAdapterContract, - 'storeBlockHeader', + 'storeBlockHeader(uint32,uint64,uint256,bytes32[],bytes32,bytes32[],(bytes32,uint256,bytes32,bytes32,uint256[2],uint256[2][2],uint256[2]))', [ (await hashiAdapterContract.provider.getNetwork()).chainId, proofResult.proofInput.nextHeaderSlot, @@ -163,11 +163,19 @@ export async function postUpdateOnChain( hashiInfo.blockNumberProof.map(x => '0x' + x), '0x' + hashiInfo.blockHash, hashiInfo.blockHashProof.map(x => '0x' + x), + { ...update, ...solidityProof }, ], new Web3(rpcEndpoint), transactionSpeed, true, ); + } else { + await lightClientContract.postUpdateOnChain({ + ...update, + a: proofResult.proof.pi_a, + b: proofResult.proof.pi_b, + c: proofResult.proof.pi_c, + }); } const transactionSlot = proofResult.proofInput.nextHeaderSlot; @@ -203,7 +211,7 @@ async function handleFailure( isDrainRunning = false; return [failedNumber, isDrainRunning]; } - log(error, 'ERROR occurred in ${scopeError}', 'will retry'); + log(error, `ERROR occurred in ${scopeError}`, 'will retry'); failedNumber++; await sleep(10000);