Skip to content

Commit

Permalink
Add method on lightclient to verify transcation and topic inclusion
Browse files Browse the repository at this point in the history
  • Loading branch information
themicp committed Oct 26, 2023
1 parent edca928 commit cac28ba
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 36 deletions.
42 changes: 11 additions & 31 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,23 @@
import { bytesToHex, formatReceipt, getEnv } from './utils.js';
import { getEnv } from './utils.js';
import { EthAPI } from './eth.js';
import { LightClientAPI } from './lightclient.js';
import { TrieWrapper} from './triewrapper.js';
import { Receipt, UserInput } from './types.js';
import assert from 'assert';
import { UserInput } from './types.js';

const CONTRACT_ADDRESS = getEnv("CONTRACT_ADDRESS")

async function isTopicInTransaction(api: EthAPI, lightClient: LightClientAPI, input: UserInput) {
const block = await api.getBlock(input.blockNumber);

const receipts: Receipt[] = (await api.getBlockTransactionReceipts(input.blockNumber)).map(formatReceipt);
const requestedTxReceipt = receipts.find((r) => r.transactionHash === input.transactionHash);
if (!requestedTxReceipt) throw new Error(`Could not find receipt for transaction ${input.transactionHash} in block ${input.blockNumber}`);

const transactionIndex = parseInt(requestedTxReceipt.transactionIndex, 16);
const receiptsTrie = await TrieWrapper.trieFromReceipts(receipts);
assert(
block.receiptsRoot.slice(2) === bytesToHex(receiptsTrie.root()),
`Expected receipts root (${block.receiptsRoot}) doesn't match the actual (${bytesToHex(receiptsTrie.root())})`);
const proof = await TrieWrapper.createProof(receiptsTrie, transactionIndex);

const isValidReceipt = true;
// const isValidReceipt = await lightClient.verify_receipt(
// block.receiptsRoot.slice(2),
// proof.map((p) => bytesToHex(p)),
// TrieWrapper.encodeKey(transactionIndex)
// );

if (isValidReceipt) {
return requestedTxReceipt.logs.find(log => log[1].includes(input.topic)) !== undefined;
}
}
const CONTRACT_ADDRESS = getEnv("CONTRACT_ADDRESS")

const main = async () => {
const api = new EthAPI()
const lightClient = new LightClientAPI(CONTRACT_ADDRESS);
await lightClient.init()

const input: UserInput = {
blockNumber: 17875570,
transactionHash: '0x022edd6e5e56c918b0ec5177ec41569e606957af7d16d9e9e65174ed522830dc',
topic: '0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196'
};

console.log(await lightClient.verifyTopicInTransaction(api, input));

// const t = await api.getBeaconBlock(7061552);
// const update = await api.getUpdate(864);
// await lightClient.applyNewUpdate(update, 864);
Expand Down
66 changes: 61 additions & 5 deletions src/lightclient.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'
import { getEnv } from './utils.js'
import { bytesToHex, formatReceipt, getEnv } from './utils.js'
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"
import { GasPrice } from '@cosmjs/stargate'
import { GasPrice, SearchByHeightQuery, SearchTxQuery } from '@cosmjs/stargate'
import * as capella from '@lodestar/types/capella'
import { Receipt, UserInput } from './types.js'
import { EthAPI } from './eth.js'
import { TrieWrapper } from './triewrapper.js'
import assert from 'assert';

export class LightClientAPI {
private myAddress: string
private client: SigningCosmWasmClient

constructor(
private address: string,
private mnemonic = getEnv("MNEMONIC"),
private mnemonic = getEnv("MNEMONIC"),
private rpcUrl = getEnv("AXELAR_RPC_URL")
) {}

Expand All @@ -33,10 +37,10 @@ export class LightClientAPI {
console.log("Error applying update for period", period, e)
return false
}

const contractPeriod = await this.getPeriod();
console.log("Current contract period after update", contractPeriod)

return true
}

Expand All @@ -45,11 +49,63 @@ export class LightClientAPI {
return Math.floor(res.finalized_header.slot / 32 / 256)
}

async verify_proof(msg: any): Promise<any> {
return this.execute(msg);
}

async verify_topic_inclusion(msg: any): Promise<any> {
return this.execute(msg);
}

private async query(msg: any): Promise<any> {
return await this.client.queryContractSmart(this.address, msg)
}

private async execute(msg: any): Promise<any> {
return await this.client.execute(this.myAddress, this.address, msg, 'auto')
}

async verifyTopicInTransaction(api: EthAPI, input: UserInput): Promise<boolean> {
const block = await api.getBlock(input.blockNumber);

const receipts: Receipt[] = (await api.getBlockTransactionReceipts(input.blockNumber)).map(formatReceipt);
const requestedTxReceipt = receipts.find((r) => r.transactionHash === input.transactionHash);
if (!requestedTxReceipt) throw new Error(`Could not find receipt for transaction ${input.transactionHash} in block ${input.blockNumber}`);

const transactionIndex = parseInt(requestedTxReceipt.transactionIndex, 16);
const receiptsTrie = await TrieWrapper.trieFromReceipts(receipts);
assert(
block.receiptsRoot.slice(2) === bytesToHex(receiptsTrie.root()),
`Expected receipts root (${block.receiptsRoot}) doesn't match the actual (${bytesToHex(receiptsTrie.root())})`);
const proof = await TrieWrapper.createProof(receiptsTrie, transactionIndex);

const response = await this.verify_proof({
VerifyProof: {
proof: proof.map(n => `0x${Buffer.from(n).toString('hex')}`),
key: Buffer.from(TrieWrapper.encodeKey(transactionIndex)).toString('hex'),
root: block.receiptsRoot
}
});
// wanted: 276233
// used: 211619

const receiptEncoded = response.events
.find((event: any) =>
event.type === 'wasm' &&
event.attributes.find((a: any) => a.key === 'result')
)?.attributes.find((a: any) => a.key === 'result')?.value;
if (parseInt(receiptEncoded, 16) !== 0) {
const response = await this.verify_topic_inclusion({
VerifyTopicInclusion: {
receipt: `0x${receiptEncoded}`,
topic: input.topic,
}
});
// "gasWanted": 169275,
// "gasUsed": 135219
return response.events.find((e: any) => e.type === 'wasm').attributes.find((a: any) => a.key === 'result').value === 'true';
} else {
return false;
}
}
}

0 comments on commit cac28ba

Please sign in to comment.