Skip to content

Commit

Permalink
fix: inclusion proof hash shall have reverse order (#405)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrwbabylonlab authored Nov 28, 2024
1 parent 6900d86 commit a97bddb
Show file tree
Hide file tree
Showing 25 changed files with 195 additions and 109 deletions.
2 changes: 1 addition & 1 deletion e2e/constants/staking.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";

export const STAKING_AMOUNT_SAT = 50000;
export const STAKING_AMOUNT_BTC = satoshiToBtc(STAKING_AMOUNT_SAT);
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Connect/ConnectSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useOnClickOutside } from "usehooks-ts";
import { useHealthCheck } from "@/app/hooks/useHealthCheck";
import { useAppState } from "@/app/state";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";
import { trim } from "@/utils/trim";

Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Connect/ConnectedSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useOnClickOutside } from "usehooks-ts";

import { useAppState } from "@/app/state";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";
import { trim } from "@/utils/trim";

Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Delegations/Delegation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import {
} from "@/app/types/delegations";
import { shouldDisplayPoints } from "@/config";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { durationTillNow } from "@/utils/formatTime";
import { satoshiToBtc } from "@/utils/btc";
import { getState, getStateTooltip } from "@/utils/getState";
import { maxDecimals } from "@/utils/maxDecimals";
import { durationTillNow } from "@/utils/time";
import { trim } from "@/utils/trim";

import { DelegationPoints } from "../Points/DelegationPoints";
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Modals/PreviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
import { useNetworkInfo } from "@/app/hooks/api/useNetworkInfo";
import { useIsMobileView } from "@/app/hooks/useBreakpoint";
import { getNetworkConfig } from "@/config/network.config";
import { blocksToDisplayTime } from "@/utils/blocksToDisplayTime";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";
import { blocksToDisplayTime } from "@/utils/time";

interface PreviewModalProps {
isOpen: boolean;
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Stakers/Staker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";

import { Hash } from "../Hash/Hash";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import blue from "@/app/assets/blue-check.svg";
import { Hash } from "@/app/components/Hash/Hash";
import { FinalityProviderState } from "@/app/types/finalityProviders";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";

interface FinalityProviderProps {
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Staking/Form/StakingAmount.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeEvent, FocusEvent, useEffect, useState } from "react";

import { getNetworkConfig } from "@/config/network.config";
import { btcToSatoshi, satoshiToBtc } from "@/utils/btcConversions";
import { btcToSatoshi, satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";

import { validateDecimalPoints } from "./validation/validation";
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Staking/Form/StakingFee.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";

import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { getFeeRateFromMempool } from "@/utils/getFeeRateFromMempool";
import { Fees } from "@/utils/wallet/btc_wallet_provider";

Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Staking/Form/StakingTime.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeEvent, FocusEvent, useEffect, useState } from "react";

import { getNetworkConfig } from "@/config/network.config";
import { blocksToDisplayTime } from "@/utils/blocksToDisplayTime";
import { blocksToDisplayTime } from "@/utils/time";

import { validateNoDecimalPoints } from "./validation/validation";

Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Stats/Stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { memo } from "react";

import { useSystemStats } from "@/app/hooks/api/useSystemStats";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";

import { StatItem } from "./StatItem";
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Summary/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useAppState } from "@/app/state";
import { useDelegationState } from "@/app/state/DelegationState";
import { shouldDisplayPoints } from "@/config";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";
import { Network } from "@/utils/wallet/btc_wallet_provider";

Expand Down
26 changes: 13 additions & 13 deletions src/app/hooks/services/useTransactionService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useCosmosWallet } from "@/app/context/wallet/CosmosWalletProvider";
import { useAppState } from "@/app/state";
import { BbnStakingParamsVersion, Params } from "@/app/types/networkInfo";
import { deriveMerkleProof } from "@/utils/btc";
import { reverseBuffer } from "@/utils/buffer";
import {
clearTxSignatures,
extractSchnorrSignaturesFromTransaction,
uint8ArrayToHex,
} from "@/utils/delegations";
import { getFeeRateFromMempool } from "@/utils/getFeeRateFromMempool";
import { getTxInfo, getTxMerkleProof, MerkleProof } from "@/utils/mempool_api";
import { getTxInfo, getTxMerkleProof } from "@/utils/mempool_api";

import { useNetworkFees } from "../api/useNetworkFees";

Expand Down Expand Up @@ -742,27 +744,25 @@ const checkWalletConnection = (
const getInclusionProof = async (
stakingTx: Transaction,
): Promise<btcstaking.InclusionProof> => {
// TODO: Use the hook instead
// Get the merkle proof
let txMerkleProof: MerkleProof;
try {
// TODO: Use the hook instead
txMerkleProof = await getTxMerkleProof(stakingTx.getId());
} catch (err) {
throw new Error("Failed to get the merkle proof", { cause: err });
}
const { pos, merkle } = await getTxMerkleProof(stakingTx.getId());
const proofHex = deriveMerkleProof(merkle);

// TODO: Use the hook instead
const txInfo = await getTxInfo(stakingTx.getId());
const blockHash = txInfo.status.block_hash;
const {
status: { blockHash },
} = await getTxInfo(stakingTx.getId());

const hash = Uint8Array.from(Buffer.from(blockHash, "hex"));
const hash = reverseBuffer(Uint8Array.from(Buffer.from(blockHash, "hex")));
const inclusionProofKey: btccheckpoint.TransactionKey =
btccheckpoint.TransactionKey.fromPartial({
index: txMerkleProof.pos,
index: pos,
hash,
});
return btcstaking.InclusionProof.fromPartial({
key: inclusionProofKey,
proof: Uint8Array.from(Buffer.from(txMerkleProof.proofHex, "hex")),
proof: Uint8Array.from(Buffer.from(proofHex, "hex")),
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FaBitcoin } from "react-icons/fa";

import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";

interface Amount {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useAppState } from "@/app/state";
import { DelegationV2StakingState as state } from "@/app/types/delegationsV2";
import { BbnStakingParamsVersion } from "@/app/types/networkInfo";
import { Hint } from "@/components/common/Hint";
import { blocksToDisplayTime } from "@/utils/blocksToDisplayTime";
import { blocksToDisplayTime } from "@/utils/time";

interface StatusProps {
value: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Hint } from "@/components/common/Hint";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";

interface DelegationProps {
Expand Down
13 changes: 13 additions & 0 deletions src/utils/btcConversions.ts → src/utils/btc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,16 @@ export function satoshiToBtc(satoshi: number): number {
export function btcToSatoshi(btc: number): number {
return Math.round(btc * 1e8);
}

/**
* Derives the merkle proof from the list of hex strings. Note the
* sibling hashes are reversed from hex before concatenation.
* @param merkle - The merkle proof hex strings.
* @returns The merkle proof in hex string format.
*/
export const deriveMerkleProof = (merkle: string[]) => {
const proofHex = merkle.reduce((acc: string, m: string) => {
return acc + Buffer.from(m, "hex").reverse().toString("hex");
}, "");
return proofHex;
};
17 changes: 17 additions & 0 deletions src/utils/buffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Reverses the order of bytes in a buffer.
* @param buffer - The buffer to reverse.
* @returns A new buffer with the bytes reversed.
*/
export const reverseBuffer = (buffer: Uint8Array): Uint8Array => {
if (buffer.length < 1) return buffer;
let j = buffer.length - 1;
let tmp = 0;
for (let i = 0; i < buffer.length / 2; i++) {
tmp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = tmp;
j--;
}
return buffer;
};
35 changes: 0 additions & 35 deletions src/utils/formatTime.ts

This file was deleted.

34 changes: 23 additions & 11 deletions src/utils/mempool_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { mempoolApiUrl } = getNetworkConfig();

export interface MerkleProof {
blockHeight: number;
proofHex: string;
merkle: string[];
pos: number;
}

Expand All @@ -21,9 +21,9 @@ interface TxInfo {
fee: number;
status: {
confirmed: boolean;
block_height: number;
block_hash: string;
block_time: number;
blockHeight: number;
blockHash: string;
blockTime: number;
};
}

Expand Down Expand Up @@ -243,7 +243,24 @@ export async function getTxInfo(txId: string): Promise<TxInfo> {
const err = await response.text();
throw new ServerError(err, response.status);
}
return await response.json();
const { txid, version, locktime, vin, vout, size, weight, fee, status } =
await response.json();
return {
txid,
version,
locktime,
vin,
vout,
size,
weight,
fee,
status: {
confirmed: status.confirmed,
blockHeight: status.block_height,
blockHash: status.block_hash,
blockTime: status.block_time,
},
};
}

/**
Expand All @@ -267,15 +284,10 @@ export async function getTxMerkleProof(txId: string): Promise<MerkleProof> {
if (!block_height || !merkle.length || !pos) {
throw new Error("Invalid transaction merkle proof result returned");
}
// The merkle proof from mempool is a list of hex strings,
// so we need to concatenate them to form the final proof
const proofHex = merkle.reduce((acc: string, m: string) => {
return acc + m;
}, "");

return {
blockHeight: block_height,
proofHex,
merkle,
pos,
};
}
Expand Down
36 changes: 36 additions & 0 deletions src/utils/blocksToDisplayTime.ts → src/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
differenceInCalendarDays,
differenceInWeeks,
formatDistanceStrict,
formatDuration,
intervalToDuration,
} from "date-fns";

const BLOCKS_PER_HOUR = 6;
Expand Down Expand Up @@ -52,3 +54,37 @@ export const blocksToDisplayTime = (blocks: number | undefined): string => {
roundingMethod: "ceil",
});
};

interface Duration {
years?: number;
months?: number;
weeks?: number;
days?: number;
hours?: number;
minutes?: number;
seconds?: number;
}

export const durationTillNow = (time: string, currentTime: number) => {
if (!time || time.startsWith("000")) return "Ongoing";

const duration = intervalToDuration({
end: currentTime,
start: new Date(time),
});
let format: (keyof Duration)[] = ["days", "hours", "minutes"];

if (!duration.days && !duration.hours && !duration.minutes) {
format.push("seconds");
}

const formattedTime = formatDuration(duration, {
format,
});

if (formattedTime) {
return `${formattedTime} ago`;
} else {
return "Just now";
}
};
Loading

0 comments on commit a97bddb

Please sign in to comment.