Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: inclusion proof hash shall have reverse order #405

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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