Skip to content

Commit

Permalink
chore: forge fmt
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Hill <[email protected]>
  • Loading branch information
gregdhill committed Nov 1, 2023
1 parent 9b62efe commit 02f94ef
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 435 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: test

on: workflow_dispatch
on: [pull_request]

env:
FOUNDRY_PROFILE: ci
Expand All @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: true

name: Foundry project
name: Foundry
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -22,6 +22,11 @@ jobs:
with:
version: nightly

- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge --version
Expand Down
102 changes: 24 additions & 78 deletions src/bridge/BitcoinTx.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ library BitcoinTx {
/// @dev `lock_time` from raw Bitcoin transaction data.
/// Encoded as 4-bytes unsigned integer, little endian.
bytes4 locktime;
// This struct doesn't contain `__gap` property as the structure is not
// stored, it is used as a function's calldata argument.
}

/// @notice Represents data needed to perform a Bitcoin SPV proof.
Expand All @@ -128,44 +126,26 @@ library BitcoinTx {
/// @notice Single byte-string of 80-byte bitcoin headers,
/// lowest height first.
bytes bitcoinHeaders;
// This struct doesn't contain `__gap` property as the structure is not
// stored, it is used as a function's calldata argument.
}

/// @notice Validates the SPV proof of the Bitcoin transaction.
/// Reverts in case the validation or proof verification fail.
/// @param txInfo Bitcoin transaction data.
/// @param proof Bitcoin proof data.
/// @return txHash Proven 32-byte transaction hash.
function validateProof(
BridgeState.Storage storage self,
Info memory txInfo,
Proof memory proof
) internal view returns (bytes32 txHash) {
require(
txInfo.inputVector.validateVin(),
"Invalid input vector provided"
);
require(
txInfo.outputVector.validateVout(),
"Invalid output vector provided"
);
function validateProof(BridgeState.Storage storage self, Info memory txInfo, Proof memory proof)
internal
view
returns (bytes32 txHash)
{
require(txInfo.inputVector.validateVin(), "Invalid input vector provided");
require(txInfo.outputVector.validateVout(), "Invalid output vector provided");

txHash = abi
.encodePacked(
txInfo.version,
txInfo.inputVector,
txInfo.outputVector,
txInfo.locktime
)
.hash256View();
txHash =
abi.encodePacked(txInfo.version, txInfo.inputVector, txInfo.outputVector, txInfo.locktime).hash256View();

require(
txHash.prove(
proof.bitcoinHeaders.extractMerkleRootLE(),
proof.merkleProof,
proof.txIndexInBlock
),
txHash.prove(proof.bitcoinHeaders.extractMerkleRootLE(), proof.merkleProof, proof.txIndexInBlock),
"Tx merkle proof is not valid for provided header and tx hash"
);

Expand All @@ -179,12 +159,9 @@ library BitcoinTx {
/// Reverts in case the evaluation fails.
/// @param bitcoinHeaders Bitcoin headers chain being part of the SPV
/// proof. Used to extract the observed proof difficulty.
function evaluateProofDifficulty(
BridgeState.Storage storage self,
bytes memory bitcoinHeaders
) internal view {
function evaluateProofDifficulty(BridgeState.Storage storage self, bytes memory bitcoinHeaders) internal view {
IRelay relay = self.relay;

// for testing
if (!relay.difficultyCheckEnabled()) {
return;
Expand All @@ -194,9 +171,7 @@ library BitcoinTx {
uint256 previousEpochDifficulty = relay.getPrevEpochDifficulty();

uint256 requestedDiff = 0;
uint256 firstHeaderDiff = bitcoinHeaders
.extractTarget()
.calculateDifficulty();
uint256 firstHeaderDiff = bitcoinHeaders.extractTarget().calculateDifficulty();

if (firstHeaderDiff == currentEpochDifficulty) {
requestedDiff = currentEpochDifficulty;
Expand All @@ -208,18 +183,9 @@ library BitcoinTx {

uint256 observedDiff = bitcoinHeaders.validateHeaderChain();

require(
observedDiff != ValidateSPV.getErrBadLength(),
"Invalid length of the headers chain"
);
require(
observedDiff != ValidateSPV.getErrInvalidChain(),
"Invalid headers chain"
);
require(
observedDiff != ValidateSPV.getErrLowWork(),
"Insufficient work in a header"
);
require(observedDiff != ValidateSPV.getErrBadLength(), "Invalid length of the headers chain");
require(observedDiff != ValidateSPV.getErrInvalidChain(), "Invalid headers chain");
require(observedDiff != ValidateSPV.getErrLowWork(), "Insufficient work in a header");

require(
observedDiff >= requestedDiff * self.txProofDifficultyFactor,
Expand All @@ -236,8 +202,6 @@ library BitcoinTx {
uint256 outputStartingIndex;
// The number of outputs in the transaction.
uint256 outputsCount;
// This struct doesn't contain `__gap` property as the structure is not
// stored, it is used as a function's memory argument.
}

/// @notice Processes the Bitcoin transaction output vector.
Expand All @@ -247,16 +211,10 @@ library BitcoinTx {
/// must be validated using e.g. `BTCUtils.validateVout` function
/// before it is passed here.
/// @return value Outcomes of the processing.
function getTxOutputValue(
bytes32 scriptPubKeyHash,
bytes memory txOutputVector
) internal returns (uint64 value) {
function getTxOutputValue(bytes32 scriptPubKeyHash, bytes memory txOutputVector) internal returns (uint64 value) {
// Determining the total number of transaction outputs in the same way as
// for number of inputs. See `BitcoinTx.outputVector` docs for more details.
(
uint256 outputsCompactSizeUintLength,
uint256 outputsCount
) = txOutputVector.parseVarInt();
(uint256 outputsCompactSizeUintLength, uint256 outputsCount) = txOutputVector.parseVarInt();

// To determine the first output starting index, we must jump over
// the compactSize uint which prepends the output vector. One byte
Expand All @@ -275,15 +233,9 @@ library BitcoinTx {
// docs in `BitcoinTx` library for more details.
uint256 outputStartingIndex = 1 + outputsCompactSizeUintLength;

return
getTxOutputValue(
scriptPubKeyHash,
txOutputVector,
TxOutputsProcessingInfo(
outputStartingIndex,
outputsCount
)
);
return getTxOutputValue(
scriptPubKeyHash, txOutputVector, TxOutputsProcessingInfo(outputStartingIndex, outputsCount)
);
}

/// @notice Processes all outputs from the transaction.
Expand All @@ -300,13 +252,10 @@ library BitcoinTx {
) internal returns (uint64 value) {
// Outputs processing loop.
for (uint256 i = 0; i < processInfo.outputsCount; i++) {
uint256 outputLength = txOutputVector
.determineOutputLengthAt(processInfo.outputStartingIndex);
uint256 outputLength = txOutputVector.determineOutputLengthAt(processInfo.outputStartingIndex);

// Extract the value from given output.
uint64 outputValue = txOutputVector.extractValueAt(
processInfo.outputStartingIndex
);
uint64 outputValue = txOutputVector.extractValueAt(processInfo.outputStartingIndex);

// The output consists of an 8-byte value and a variable length
// script. To hash that script we slice the output starting from
Expand All @@ -322,10 +271,7 @@ library BitcoinTx {
// by `outputScriptStart`. To load that position, we
// need to call `add(outputScriptStart, 32)` because
// `outputScriptStart` has 32 bytes.
outputScriptHash := keccak256(
add(txOutputVector, add(outputScriptStart, 32)),
scriptLength
)
outputScriptHash := keccak256(add(txOutputVector, add(outputScriptStart, 32)), scriptLength)
}

if (scriptPubKeyHash == outputScriptHash) {
Expand Down
70 changes: 28 additions & 42 deletions src/bridge/WitnessTx.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ library WitnessTx {
using SegWitUtils for bytes;
using ValidateSPV for bytes32;

bytes1 constant SEGWIT_MARKER = hex"00";
bytes1 constant SEGWIT_FLAG = hex"01";

/// @notice Represents a Bitcoin transaction with the witness data.
struct WitnessInfo {
/// @notice Bitcoin transaction info.
Expand Down Expand Up @@ -45,31 +48,21 @@ library WitnessTx {
/// @param txInfo Bitcoin transaction data.
/// @param proof Bitcoin proof data.
/// @return wTxHash Proven 32-byte transaction hash.
function validateWitnessProof(
WitnessInfo memory txInfo,
WitnessProof memory proof
) internal view returns (bytes32 wTxHash) {
require(
proof.coinbaseTx.outputVector.validateVout(),
"Invalid coinbase output vector provided"
);
require(
txInfo.info.inputVector.validateVin(),
"Invalid payment input vector provided"
);
require(
txInfo.info.outputVector.validateVout(),
"Invalid payment output vector provided"
);
function validateWitnessProof(WitnessInfo memory txInfo, WitnessProof memory proof)
internal
view
returns (bytes32 wTxHash)
{
require(proof.coinbaseTx.outputVector.validateVout(), "Invalid coinbase output vector provided");
require(txInfo.info.inputVector.validateVin(), "Invalid payment input vector provided");
require(txInfo.info.outputVector.validateVout(), "Invalid payment output vector provided");

bytes32 coinbaseTxHash = abi
.encodePacked(
proof.coinbaseTx.version,
proof.coinbaseTx.inputVector,
proof.coinbaseTx.outputVector,
proof.coinbaseTx.locktime
)
.hash256View();
bytes32 coinbaseTxHash = abi.encodePacked(
proof.coinbaseTx.version,
proof.coinbaseTx.inputVector,
proof.coinbaseTx.outputVector,
proof.coinbaseTx.locktime
).hash256View();

require(
coinbaseTxHash.prove(
Expand All @@ -80,32 +73,25 @@ library WitnessTx {
"Tx merkle proof is not valid for provided header and tx hash"
);

bytes32 paymentWTxId = abi
.encodePacked(
txInfo.info.version,
hex"00", // SEGWIT_MARKER
hex"01", // SEGWIT_FLAG
txInfo.info.inputVector,
txInfo.info.outputVector,
txInfo.witnessVector,
txInfo.info.locktime
)
.hash256View();
bytes32 paymentWTxId = abi.encodePacked(
txInfo.info.version,
SEGWIT_MARKER,
SEGWIT_FLAG,
txInfo.info.inputVector,
txInfo.info.outputVector,
txInfo.witnessVector,
txInfo.info.locktime
).hash256View();

require(
paymentWTxId.prove(
proof.paymentMerkleRoot,
proof.paymentProof.merkleProof,
proof.paymentProof.txIndexInBlock
proof.paymentMerkleRoot, proof.paymentProof.merkleProof, proof.paymentProof.txIndexInBlock
),
"Tx witness merkle proof is not valid for provided header and tx hash"
);

// witnessCommitment = SHA256(witnessMerkleRoot || witnessNonce)
bytes32 witnessCommitment = abi.encodePacked(
proof.paymentMerkleRoot,
proof.witnessNonce
).hash256View();
bytes32 witnessCommitment = abi.encodePacked(proof.paymentMerkleRoot, proof.witnessNonce).hash256View();

// extract coinbase commitment from tx out
bytes32 coinbaseWitnessCommitment = proof.coinbaseTx.outputVector.extractWitnessCommitment();
Expand Down
Loading

0 comments on commit 02f94ef

Please sign in to comment.