Skip to content

Commit

Permalink
Include coinbase data in the assembleBitcoinSpvProof function
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-zimnoch committed Jan 17, 2024
1 parent b240a97 commit bc385f8
Show file tree
Hide file tree
Showing 9 changed files with 597 additions and 19 deletions.
54 changes: 51 additions & 3 deletions typescript/src/lib/bitcoin/spv.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BitcoinTx, BitcoinTxHash } from "./tx"
import { BitcoinTx, BitcoinTxHash, extractBitcoinRawTxVectors } from "./tx"
import { BitcoinClient } from "./client"
import { BigNumber } from "ethers"
import {
Expand Down Expand Up @@ -29,6 +29,17 @@ export interface BitcoinSpvProof {
* 80-byte-long. The block header with the lowest height is first.
*/
bitcoinHeaders: Hex

/**
* The sha256 preimage of the coinbase transaction hash i.e.,
* the sha256 hash of the coinbase transaction.
*/
coinbasePreimage: Hex

/**
* Merkle proof of coinbase transaction inclusion in a block.
*/
coinbaseProof: Hex
}

/**
Expand Down Expand Up @@ -101,10 +112,34 @@ export async function assembleBitcoinSpvProof(

const merkleProof = createMerkleProof(merkleBranch)

const coinbaseTxHash = await bitcoinClient.getCoinbaseTxHash(txBlockHeight)

const coinbaseTx = extractBitcoinRawTxVectors(
await bitcoinClient.getRawTransaction(coinbaseTxHash)
)

const coinbasePreimage = BitcoinHashUtils.computeSha256(
Hex.from(
`${coinbaseTx.version.toString()}` +
`${coinbaseTx.inputs.toString()}` +
`${coinbaseTx.outputs.toString()}` +
`${coinbaseTx.locktime.toString()}`
)
)

const coinbaseMerkleBranch = await bitcoinClient.getTransactionMerkle(
coinbaseTxHash,
txBlockHeight
)

const coinbaseMerkleProof = createMerkleProof(coinbaseMerkleBranch)

const proof = {
merkleProof: merkleProof,
txIndexInBlock: merkleBranch.position,
bitcoinHeaders: headersChain,
coinbasePreimage: coinbasePreimage,
coinbaseProof: coinbaseMerkleProof,
}

return { ...transaction, ...proof }
Expand Down Expand Up @@ -159,19 +194,25 @@ export async function validateBitcoinSpvProof(
bitcoinClient
)

if (
proof.merkleProof.toBuffer().length !==
proof.coinbaseProof.toBuffer().length
) {
throw new Error("Tx not on same level of merkle tree as coinbase")
}

const bitcoinHeaders: BitcoinHeader[] =
BitcoinHeaderSerializer.deserializeHeadersChain(proof.bitcoinHeaders)
if (bitcoinHeaders.length != requiredConfirmations) {
throw new Error("Wrong number of confirmations")
}

const merkleRootHash: Hex = bitcoinHeaders[0].merkleRootHash
const intermediateNodeHashes: Hex[] = splitMerkleProof(proof.merkleProof)

validateMerkleTree(
transactionHash,
merkleRootHash,
intermediateNodeHashes,
splitMerkleProof(proof.merkleProof),
proof.txIndexInBlock
)

Expand All @@ -180,6 +221,13 @@ export async function validateBitcoinSpvProof(
previousDifficulty,
currentDifficulty
)

validateMerkleTree(
BitcoinHashUtils.computeSha256(proof.coinbasePreimage).reverse(),
merkleRootHash,
splitMerkleProof(proof.coinbaseProof),
0
)
}

/**
Expand Down
8 changes: 6 additions & 2 deletions typescript/src/lib/ethereum/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ export class EthereumBridge
merkleProof: sweepProof.merkleProof.toPrefixedString(),
txIndexInBlock: sweepProof.txIndexInBlock,
bitcoinHeaders: sweepProof.bitcoinHeaders.toPrefixedString(),
coinbasePreimage: sweepProof.coinbasePreimage.toPrefixedString(),
coinbaseProof: sweepProof.coinbaseProof.toPrefixedString(),
}

const mainUtxoParam = {
Expand Down Expand Up @@ -391,9 +393,11 @@ export class EthereumBridge
}

const redemptionProofParam = {
merkleProof: `0x${redemptionProof.merkleProof}`,
merkleProof: redemptionProof.merkleProof.toPrefixedString(),
txIndexInBlock: redemptionProof.txIndexInBlock,
bitcoinHeaders: `0x${redemptionProof.bitcoinHeaders}`,
bitcoinHeaders: redemptionProof.bitcoinHeaders.toPrefixedString(),
coinbasePreimage: redemptionProof.coinbasePreimage.toPrefixedString(),
coinbaseProof: redemptionProof.coinbaseProof.toPrefixedString(),
}

const mainUtxoParam = {
Expand Down
44 changes: 44 additions & 0 deletions typescript/test/data/deposit-sweep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,8 @@ export interface DepositSweepProofTestData {
latestBlockHeight: number
headersChain: Hex
transactionMerkleBranch: BitcoinTxMerkleBranch
coinbaseRawTransaction: BitcoinRawTx
coinbaseMerkleBranch: BitcoinTxMerkleBranch
}
expectedSweepProof: {
sweepTx: BitcoinRawTxVectors
Expand Down Expand Up @@ -563,6 +565,38 @@ export const depositSweepProof: DepositSweepProofTestData = {
],
position: 6,
},
coinbaseRawTransaction: {
transactionHex:
"02000000000101000000000000000000000000000000000000000000000000000" +
"0000000000000ffffffff4803bb05210445c21c62425443506f6f6cfabe6d6d97" +
"92ca7580b0dccdb4465ab26f697e165c536838032a466ef25b25bb7bebb3ae040" +
"000000d6531d503040db15755000000000000ffffffff0212304d000000000017" +
"a9147bef0b4a4dafa77b2ec52b81659cbcf0d9a91487870000000000000000266" +
"a24aa21a9ed8a716e1e3e8691cfc14df968505d88fae2e240b7f4ca4d59871992" +
"a63c9900640120000000000000000000000000000000000000000000000000000" +
"000000000000000000000",
},
coinbaseMerkleBranch: {
blockHeight: 2164155,
merkle: [
Hex.from(
"d654db76daa53b61becba19a542c6156a725d0bce3d0f3a57d713c9a9498ab95"
),
Hex.from(
"df2a8c9cded17679ecacc119d92bfa5dc795bb80284e320e80e4f9f93d0e5ba4"
),
Hex.from(
"b7d63f60c09609472aa68fbb6380cffc87b4d921a26edc8b2626154145d603be"
),
Hex.from(
"a51612d3f3f857e95803a4d86aa6dbbe2e756dc2ed6cc0e04630e8baf597e377"
),
Hex.from(
"a00501650e0c4f8a1e07a5d6d5bc5e75e4c75de61a65f0410cce354bbae78686"
),
],
position: 0,
},
},
expectedSweepProof: {
sweepTx: {
Expand Down Expand Up @@ -613,6 +647,16 @@ export const depositSweepProof: DepositSweepProofTestData = {
"99b8e9db517e36f000000000000a494b8034039e7855b75563ab83c9410dd67e89b" +
"b58e6cd93b85290a885dd749f4d61c62ed3e031ad9a83746"
),
coinbasePreimage: Hex.from(
"0248a67dec36c38a485ad920afd89dcf082e7e570390380890e3a9465662f449"
),
coinbaseProof: Hex.from(
"95ab98949a3c717da5f3d0e3bcd025a756612c549aa1cbbe613ba5da76db54d6a45" +
"b0e3df9f9e4800e324e2880bb95c75dfa2bd919c1acec7976d1de9c8c2adfbe03d6" +
"45411526268bdc6ea221d9b487fccf8063bb8fa62a470996c0603fd6b777e397f5b" +
"ae83046e0c06cedc26d752ebedba66ad8a40358e957f8f3d31216a58686e7ba4b35" +
"ce0c41f0651ae65dc7e4755ebcd5d6a5071e8a4f0c0e650105a0"
),
},
mainUtxo: NO_MAIN_UTXO,
},
Expand Down
Loading

0 comments on commit bc385f8

Please sign in to comment.