Skip to content
This repository was archived by the owner on Jun 21, 2024. It is now read-only.

Commit

Permalink
more comments and proof tests
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Hill <gregorydhill@outlook.com>
  • Loading branch information
gregdhill committed Jul 13, 2020
1 parent fc10c1b commit 3153929
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 112 deletions.
16 changes: 12 additions & 4 deletions scripts/fetch.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
#!/bin/bash

TXID=b7c1e5feb5a79d82b6502bf160e3787f0f4189a30ffc2f3a9ef641d0592ae7b1
# https://github.com/Blockstream/esplora

curl https://blockstream.info/testnet/api/tx/${TXID}/merkle-proof --output -
## Transaction

echo -e "\n"
TXID=9f0370848f7bbf67908808997661a320af4f0075dce313e2934a576ed8204059

curl https://blockstream.info/testnet/api/tx/${TXID}/hex --output -
curl https://blockstream.info/api/tx/${TXID}/merkle-proof --output -
curl https://blockstream.info/api/tx/${TXID}/hex --output -

## Block

HASH=00000000000000000021868c2cefc52a480d173c849412fe81c4e5ab806f94ab

curl https://blockstream.info/api/block/${HASH} --output -
curl https://blockstream.info/api/block/${HASH}/raw --output - | tac | tac | xxd -p | tr -d \\n | head -c 160
11 changes: 11 additions & 0 deletions scripts/proof.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

HEIGHT=1760000
INDEX=0

HASH=$(bitcoin-cli -testnet getblockhash ${HEIGHT})
TXID=$(bitcoin-cli -testnet getblock ${HASH} | jq ".tx[${INDEX}]")

echo ${HASH}

bitcoin-cli -testnet gettxoutproof "[${TXID}]" ${HASH}
41 changes: 30 additions & 11 deletions src/IRelay.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,48 @@ interface IRelay {
event ChainReorg(bytes32 indexed from, bytes32 indexed to, uint256 indexed id);

/**
* @notice Parses, validates and stores Bitcoin block header1 to mapping
* @param header Raw Bitcoin block header bytes (80 bytes)
* @return bytes32 Bitcoin-like double sha256 hash of submitted block
* @notice Parses, validates and stores a block header
* @param header Raw block header bytes (80 bytes)
*/
function submitBlockHeader(bytes calldata header) external;

/**
* @notice Parses, validates and stores a batch of headers
* @param headers Raw block headers (80* bytes)
*/
function submitBlockHeaderBatch(bytes calldata headers) external;

/**
* @notice Gets the height of an included block
* @param digest Hash of the referenced block
* @return Height of the stored block, reverts if not found
*/
function getBlockHeight(bytes32 digest) external view returns (uint32);

/**
* @notice Gets the hash of an included block
* @param height Height of the referenced block
* @return Hash of the stored block, reverts if not found
*/
function getBlockHash(uint32 height) external view returns (bytes32);

/**
* @notice Gets the hash and height for the best tip
* @return digest Hash of stored block
* @return height Height of stored block
*/
function getBestBlock() external view returns (bytes32 digest, uint32 height);

/**
* @notice verifies that a transaction is included in a block
* @param height height of block that included transaction
* @param index index of transaction in the block's tx merkle tree
* @param txid transaction identifier
* @param proof merkle proof
* @param confirmations required confirmations (insecure)
* @param insecure check custom inclusion confirmations
* @return true if _txid is included, false otherwise
* @notice Verifies that a transaction is included in a block
* @param height Height of block that included transaction
* @param index Index of transaction in the block's tx merkle tree
* @param txid Transaction identifier (little endian)
* @param header Raw block header (80 bytes)
* @param proof Merkle proof
* @param confirmations Required confirmations (insecure)
* @param insecure Check custom inclusion confirmations
* @return True if txid is included, false otherwise
*/
function verifyTx(
uint32 height,
Expand Down
86 changes: 57 additions & 29 deletions src/Parser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,40 @@ library Parser {
// EXCEPTION MESSAGES
string constant ERR_INVALID_OUTPUT = "Invalid output";

function extractInputLength(bytes memory _rawTx) internal pure returns (uint, uint) {
uint length = _rawTx.length;
/**
* @notice Extracts number of inputs and ending index
* @param rawTx Raw transaction
* @return Number of inputs
* @return Scanner end position
*/
function extractInputLength(bytes memory rawTx) internal pure returns (uint, uint) {
uint length = rawTx.length;

// skip version
uint pos = 4;

bytes memory segwit = _rawTx.slice(pos, 2);
bytes memory segwit = rawTx.slice(pos, 2);
if (segwit[0] == 0x00 && segwit[1] == 0x01) {
pos = pos + 2;
}

uint varIntLen = _rawTx.slice(pos, length - pos).determineVarIntDataLength();
uint varIntLen = rawTx.slice(pos, length - pos).determineVarIntDataLength();
if (varIntLen == 0) {
varIntLen = 1;
}

uint numInputs = _rawTx.slice(pos, varIntLen).bytesToUint();
uint numInputs = rawTx.slice(pos, varIntLen).bytesToUint();
pos = pos + varIntLen;

for (uint i = 0; i < numInputs; i++) {
pos = pos + 32;
pos = pos + 4;
// read varInt for script sig
uint scriptSigvarIntLen = _rawTx.slice(pos, length - pos).determineVarIntDataLength();
uint scriptSigvarIntLen = rawTx.slice(pos, length - pos).determineVarIntDataLength();
if (scriptSigvarIntLen == 0) {
scriptSigvarIntLen = 1;
}
uint scriptSigLen = _rawTx.slice(pos, scriptSigvarIntLen).bytesToUint();
uint scriptSigLen = rawTx.slice(pos, scriptSigvarIntLen).bytesToUint();
pos = pos + scriptSigvarIntLen;
// get script sig
pos = pos + scriptSigLen;
Expand All @@ -51,80 +57,102 @@ library Parser {
return (numInputs, pos);
}

function extractOutputLength(bytes memory _rawTx) internal pure returns (uint, uint) {
uint length = _rawTx.length;
/**
* @notice Extracts number of outputs and ending index
* @param rawTx Raw transaction
* @return Number of outputs
* @return Scanner end position
*/
function extractOutputLength(bytes memory rawTx) internal pure returns (uint, uint) {
uint length = rawTx.length;
uint pos = 0;

uint varIntLen = _rawTx.slice(pos, length - pos).determineVarIntDataLength();
uint varIntLen = rawTx.slice(pos, length - pos).determineVarIntDataLength();
if (varIntLen == 0) {
varIntLen = 1;
}

uint numOutputs = _rawTx.slice(pos, varIntLen).bytesToUint();
uint numOutputs = rawTx.slice(pos, varIntLen).bytesToUint();
pos = pos + varIntLen;

for (uint i = 0; i < numOutputs; i++) {
pos = pos + 8;
uint pkScriptVarIntLen = _rawTx.slice(pos, length - pos).determineVarIntDataLength();
uint pkScriptVarIntLen = rawTx.slice(pos, length - pos).determineVarIntDataLength();
if (pkScriptVarIntLen == 0) {
pkScriptVarIntLen = 1;
}
uint pkScriptLen = _rawTx.slice(pos, pkScriptVarIntLen).bytesToUint();
uint pkScriptLen = rawTx.slice(pos, pkScriptVarIntLen).bytesToUint();
pos = pos + pkScriptVarIntLen;
pos = pos + pkScriptLen;
}

return (numOutputs, pos);
}

function extractOutputAtIndex(bytes memory _outputs, uint256 _index) internal pure returns (bytes memory) {
uint length = _outputs.length;
/**
* @notice Extracts output from transaction outputs
* @param outputs Raw transaction outputs
* @param index Index of output
* @return Output bytes
*/
function extractOutputAtIndex(bytes memory outputs, uint256 index) internal pure returns (bytes memory) {
uint length = outputs.length;
uint pos = 0;

uint varIntLen = _outputs.slice(pos, length - pos).determineVarIntDataLength();
uint varIntLen = outputs.slice(pos, length - pos).determineVarIntDataLength();
if (varIntLen == 0) {
varIntLen = 1;
}

uint numOutputs = _outputs.slice(pos, varIntLen).bytesToUint();
require(numOutputs >= _index, ERR_INVALID_OUTPUT);
uint numOutputs = outputs.slice(pos, varIntLen).bytesToUint();
require(numOutputs >= index, ERR_INVALID_OUTPUT);
pos = pos + varIntLen;

uint start = pos;
for (uint i = 0; i < numOutputs; i++) {
pos = pos + 8;
uint pkScriptVarIntLen = _outputs.slice(pos, length - pos).determineVarIntDataLength();
uint pkScriptVarIntLen = outputs.slice(pos, length - pos).determineVarIntDataLength();
if (pkScriptVarIntLen == 0) {
pkScriptVarIntLen = 1;
}
uint pkScriptLen = _outputs.slice(pos, pkScriptVarIntLen).bytesToUint();
uint pkScriptLen = outputs.slice(pos, pkScriptVarIntLen).bytesToUint();
pos = pos + pkScriptVarIntLen;
pos = pos + pkScriptLen;
if (i == _index) {
return _outputs.slice(start, pos);
if (i == index) {
return outputs.slice(start, pos);
}
start = pos;
}

return "";
}

function extractOutputValue(bytes memory _out) internal pure returns (uint64) {
return _out.extractValue();
/**
* @notice Extracts the amount from a tx output
* @param out Raw transaction output
* @return Value
*/
function extractOutputValue(bytes memory out) internal pure returns (uint64) {
return out.extractValue();
}

function extractOutputScript(bytes memory _out) internal pure returns (bytes memory) {
uint length = _out.length;
/**
* @notice Extracts the script from a tx output
* @param out Raw transaction output
* @return Script bytes
*/
function extractOutputScript(bytes memory out) internal pure returns (bytes memory) {
uint length = out.length;

// skip value
uint pos = 8;
uint pkScriptVarIntLen = _out.slice(pos, length - pos).determineVarIntDataLength();
uint pkScriptVarIntLen = out.slice(pos, length - pos).determineVarIntDataLength();
if (pkScriptVarIntLen == 0) {
pkScriptVarIntLen = 1;
}

uint pkScriptLen = _out.slice(pos, pkScriptVarIntLen).bytesToUint();
uint pkScriptLen = out.slice(pos, pkScriptVarIntLen).bytesToUint();
pos = pos + pkScriptVarIntLen;
return _out.slice(pos, pkScriptLen);
return out.slice(pos, pkScriptLen);
}
}
28 changes: 14 additions & 14 deletions src/ParserDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ contract ParserDelegate {
using BytesLib for bytes;
using Parser for bytes;

function extractInputLength(bytes memory _rawTx) public pure returns (uint numInputs, uint lenInputs) {
return _rawTx.extractInputLength();
function extractInputLength(bytes memory rawTx) public pure returns (uint numInputs, uint lenInputs) {
return rawTx.extractInputLength();
}

function extractOutputLength(bytes memory _rawTx) public pure returns (uint numOutputs, uint lenOutputs) {
return _rawTx.extractOutputLength();
function extractOutputLength(bytes memory rawTx) public pure returns (uint numOutputs, uint lenOutputs) {
return rawTx.extractOutputLength();
}

function extractNumOutputs(bytes memory _rawTx) public pure returns (uint) {
(, uint lenInputs) = _rawTx.extractInputLength();
bytes memory outputs = _rawTx.slice(lenInputs, _rawTx.length - lenInputs);
function extractNumOutputs(bytes memory rawTx) public pure returns (uint) {
(, uint lenInputs) = rawTx.extractInputLength();
bytes memory outputs = rawTx.slice(lenInputs, rawTx.length - lenInputs);
(uint numOutputs, ) = outputs.extractOutputLength();
return numOutputs;
}

function extractOutputAtIndex(bytes memory _rawTx, uint256 _index) public pure returns (bytes memory) {
(, uint lenInputs) = _rawTx.extractInputLength();
return _rawTx.slice(lenInputs, _rawTx.length - lenInputs).extractOutputAtIndex(_index);
function extractOutputAtIndex(bytes memory rawTx, uint256 index) public pure returns (bytes memory) {
(, uint lenInputs) = rawTx.extractInputLength();
return rawTx.slice(lenInputs, rawTx.length - lenInputs).extractOutputAtIndex(index);
}

function extractOutputValueAtIndex(bytes memory _rawTx, uint256 _index) public pure returns (uint256) {
bytes memory output = extractOutputAtIndex(_rawTx, _index);
function extractOutputValueAtIndex(bytes memory rawTx, uint256 index) public pure returns (uint256) {
bytes memory output = extractOutputAtIndex(rawTx, index);
return output.extractOutputValue();
}

function extractOutputScriptAtIndex(bytes memory _rawTx, uint256 _index) public pure returns (bytes memory) {
bytes memory output = extractOutputAtIndex(_rawTx, _index);
function extractOutputScriptAtIndex(bytes memory rawTx, uint256 index) public pure returns (bytes memory) {
bytes memory output = extractOutputAtIndex(rawTx, index);
return output.extractOutputScript();
}
}
Loading

0 comments on commit 3153929

Please sign in to comment.