Skip to content

Commit

Permalink
Merge pull request #1 from bob-collective/feat/bitcoin-tx
Browse files Browse the repository at this point in the history
feat: add segwit parsing utils
  • Loading branch information
gregdhill authored Oct 11, 2023
2 parents 507d01b + fe7adb0 commit 98264ce
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/SegWitUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
pragma solidity ^0.8.4;

import {BTCUtils} from "./BTCUtils.sol";
import {BytesLib} from "./BytesLib.sol";

library SegWitUtils {
using BTCUtils for bytes;
using BytesLib for bytes;

bytes6 public constant WITNESS_MAGIC_BYTES = hex"6a24aa21a9ed";
uint256 public constant COINBASE_WITNESS_PK_SCRIPT_LENGTH = 38;

function isWitnessCommitment(bytes memory pkScript) internal pure returns (bool) {
return pkScript.length >= COINBASE_WITNESS_PK_SCRIPT_LENGTH && bytes6(pkScript.slice32(0)) == WITNESS_MAGIC_BYTES;
}

// https://github.com/btcsuite/btcd/blob/80f5a0ffdf363cfff27d550f9e38aa262667a7f1/blockchain/merkle.go#L192
function extractWitnessCommitment(bytes memory _vout) internal pure returns (bytes32) {
uint256 _varIntDataLen;
uint256 _nOuts;

(_varIntDataLen, _nOuts) = _vout.parseVarInt();
require(_varIntDataLen != BTCUtils.ERR_BAD_ARG, "Read overrun during VarInt parsing");

uint256 _len = 0;
uint256 _offset = 1 + _varIntDataLen;

for (uint256 _i = 0; _i < _nOuts; _i ++) {
_len = _vout.determineOutputLengthAt(_offset);
require(_len != BTCUtils.ERR_BAD_ARG, "Bad VarInt in scriptPubkey");
bytes memory _output = _vout.slice(_offset, _len);
if (_output[8] == hex"26") {
// skip 8-byte value
bytes memory _pkScript = _output.slice(9, COINBASE_WITNESS_PK_SCRIPT_LENGTH);
if (isWitnessCommitment(_pkScript)) {
return bytes32(_pkScript.slice(
WITNESS_MAGIC_BYTES.length,
COINBASE_WITNESS_PK_SCRIPT_LENGTH - WITNESS_MAGIC_BYTES.length
));
}
}
_offset += _len;
}

return hex"";
}
}
22 changes: 22 additions & 0 deletions test/SegWitUtils.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import {SegWitUtils} from "../src/SegWitUtils.sol";

import {Test, console2} from "forge-std/Test.sol";

contract SegWitUtilsTest is Test {
using SegWitUtils for bytes;

function test_IsWitnessTxOut() public {
bytes memory pkScript = hex"6a24aa21a9edaf8dcb9588f94a3adb462e80f1306d96ef6ffad72160b33cd5e90045d81e0d77";
assert(pkScript.isWitnessCommitment());
}

function test_ExtractWitnessCommitmentFromTxOut() public {
bytes memory outputVector = hex"020593cb260000000016001435f6de260c9f3bdee47524c473a6016c0c055cb90000000000000000266a24aa21a9edaf8dcb9588f94a3adb462e80f1306d96ef6ffad72160b33cd5e90045d81e0d77";
bytes32 witnessCommitment = outputVector.extractWitnessCommitment();
bytes32 coinbaseWitnessCommitment = hex"af8dcb9588f94a3adb462e80f1306d96ef6ffad72160b33cd5e90045d81e0d77";
assertEq(coinbaseWitnessCommitment, witnessCommitment);
}
}

0 comments on commit 98264ce

Please sign in to comment.