Contractless/docs/VALIDATION_TOOLS.md

13 KiB

Validation Tools

Contractless includes several command-line tools for manually inspecting hashes, addresses, messages, block headers, torrents, and partially signed transactions.

On Windows, add .exe to each command name.

When a tool asks for a wallet path, block path, torrent path, transaction path, or other file path, press <Tab> to search and auto-complete files and folders.

skein_hasher

Hashes text, a full file, or a selected byte range from a file.

This is a custom Contractless hashing tool. It is built for Contractless debugging and manual verification. Its output may not match unrelated Skein tools because Contractless uses its own helper functions, encodings, and hash-size conventions. Use this tool when you want to reproduce hashes the Contractless software expects.

Main uses:

  • Manually verify text hashes.
  • Manually verify file hashes.
  • Manually verify a byte range from a block or torrent file.
  • Create hashes that will be used by Contractless tools or debugging flows.

Usage:

skein_hasher text large|small <value>
skein_hasher file large|small <file_path>
skein_hasher bytes large|small <start_byte> <stop_byte> <file_path>

Hash sizes:

Size Meaning
small Contractless 128-bit Skein hash output
large Contractless 256-bit Skein hash output

Modes:

Mode What It Hashes
text The exact text passed as <value>
file The full contents of <file_path>
bytes The byte range from <start_byte> up to, but not including, <stop_byte>

Examples:

skein_hasher text large hello
skein_hasher file small ./blocks/testnet/1000.block
skein_hasher bytes small 0 1024 ./blocks/testnet/1000.block

Expected output examples:

Hash of text 'hello': <hash>
Hash of file <hash>
Hash of bytes 0 through 1024 of file './blocks/testnet/1000.block': <hash>

unpack_block_header

Reads a local block file by block number, decodes the block header, prints the header hash value, and prints the decoded header JSON.

Use this when you want to manually inspect the header of a block stored on disk.

Usage:

unpack_block_header <block_number>

The tool loads the block from the active network block path in settings.ini.

Expected output:

difficulty: <numeric hash value>
hash_value: <block header hash>
{
  "unmined_block": {
    "timestamp": <block timestamp>,
    "miner": "<miner short address>",
    "previous_hash": "<parent block hash>",
    "next_block_difficulty": <difficulty target>,
    "nonce": <nonce>
  },
  "vrf": <vrf value>,
  "proof": "<miner signature proof>"
}

Output fields:

Field Meaning
difficulty Numeric value derived from the block header hash. This is useful when manually comparing the block hash against the difficulty target.
hash_value Contractless hash of the block header.
unmined_block.timestamp Timestamp stored in the block header.
unmined_block.miner Short address of the miner that mined the block.
unmined_block.previous_hash Parent block hash.
unmined_block.next_block_difficulty Difficulty target used for this block.
unmined_block.nonce One-byte nonce used by the miner.
vrf Random value derived from the miner proof.
proof Miner signature proof over the unmined block header hash.

unpack_torrent

Reads a local torrent file by block number and prints the decoded torrent metadata as JSON.

Use this when you want to manually inspect the torrent metadata used to fetch, verify, and reconstruct a block.

Usage:

unpack_torrent <block_number>

The tool loads the torrent from the active network torrent path in settings.ini.

Expected output:

{
  "info": {
    "length": 0,
    "this_block_difficulty": 0,
    "timestamp": 0,
    "nonce": 0,
    "vrf": 0,
    "block_hash": "<block header hash>",
    "previous_hash": "<parent block hash>",
    "piece_length": 0,
    "info_hash": "<block file hash>",
    "pieces": [
      {
        "1": "<piece hash>"
      }
    ]
  },
  "mined_by": "<miner short address>"
}

Output fields:

Field Meaning
info.length Total byte length of the matching block file.
info.this_block_difficulty Difficulty target recorded in the torrent metadata.
info.timestamp Timestamp copied from the block header.
info.nonce Nonce copied from the block header.
info.vrf VRF value copied from the block header.
info.block_hash Header hash of the matching block.
info.previous_hash Parent block hash.
info.piece_length Number of bytes per block piece, except possibly the final piece.
info.info_hash Contractless hash of the full block file bytes.
info.pieces Piece number to piece-hash map. Each piece hash lets a node verify one downloaded block chunk.
mined_by Short address of the miner that mined the block.

If the torrent file is missing, the tool prints:

Torrent file not found: <path>

If the torrent bytes cannot be parsed, the tool prints:

Failed to parse torrent: <error>

validate_torrent_and_block_headers

Validates that a local block file, local block header, and local torrent file agree with each other.

This is an automated validation helper. It is useful when you want more than a manual unpack, but less than a full node sync/replay. The tool validates several pieces of the block and torrent relationship and prints a pass/fail line for each check.

Usage:

validate_torrent_and_block_headers <block_number>

or:

validate_torrent_and_block_headers <block_number> <miner_public_key_hex>

If you do not pass miner_public_key_hex, the tool looks up the miner public key through the live wallet registry. That lookup relies on node trust: the tool trusts the reachable node to return the correct registered public key for the miner address. The command prompts for a wallet path and decryption key so it can authenticate the lookup.

If you pass miner_public_key_hex, the tool uses that public key directly and does not need to ask the node for the miner public key.

Interactive prompts when the public key is not supplied:

Please enter the path to your wallet file:
What is your wallet decryption key?

Checks performed:

Check What It Proves
timestamp match The block header timestamp and torrent timestamp are the same.
nonce match The block header nonce and torrent nonce are the same.
wallet address match The miner address in the block header matches the mined_by address in the torrent.
block difficulty check The numeric block hash value is below the torrent difficulty target.
VRF match The VRF value in the block header matches the VRF value in the torrent.
file size check The local block file byte length matches info.length in the torrent.
block header hash check The locally computed block header hash matches info.block_hash in the torrent.
VRF validation check The VRF value verifies against the unmined block hash, miner public key, and miner proof.
VRF Proof check The miner proof is a valid signature over the unmined block hash.
piece <n> hash check Each block-file piece hashes to the value recorded in the torrent.
block hash check The full local block file hashes to the torrent info_hash.

Expected successful output shape:

timestamp match:                                                                          [PASSED]
nonce match:                                                                              [PASSED]
wallet address match:                                                                     [PASSED]
block difficulty check:                                                                   [PASSED]
VRF match:                                                                                [PASSED]
file size check:                                                                          [PASSED]
block header hash check:                                                                  [PASSED]
VRF validation check:                                                                     [PASSED]
VRF Proof check:                                                                          [PASSED]
piece 1 hash check:                                                                       [PASSED]
block hash check:                                                                         [PASSED]

Block <block_number> fully validated.

If any required check fails, the final line is:

Block <block_number> FAILED validation.

verify_address

Checks whether a directly pasted address is valid.

This tool is also documented in Wallet Tools, because address validation is useful both for wallet management and for general validation work.

Usage:

verify_address <wallet_address>

Interactive prompt:

Please enter the wallet address:

Expected output:

true

or:

false

This command expects the address itself, not a path to a file containing the address.

verify_message

Verifies a message signature against a wallet address.

This tool is also documented in Wallet Tools, because message verification is commonly used to prove wallet ownership outside of transactions.

Usage:

verify_message "<message to verify>" <wallet_address> <signature>

Interactive prompts:

Please enter the message to verify:
Please enter the wallet address:
Please enter the signature:
Please enter the path to your wallet file:
What is your wallet decryption key?

Expected output:

valid signature

or:

invalid signature

The message must match the originally signed text exactly. This command expects the wallet address and signature directly, not paths to files containing them.

verify_sign_loan_tx

Reviews, verifies, and signs a lender-created loan transaction as the borrower.

This tool is also covered in the loan documentation. In this validation document, the important point is that the tool is not a blind signer. It reads the loan JSON, rebuilds the unsigned loan transaction, checks that the hash still matches, confirms that the active wallet is the borrower, asks the borrower to confirm the human-readable loan terms, then writes a fully signed transaction JSON.

Usage:

verify_sign_loan_tx <path/to/file.json>

The current usage text printed by the tool is:

Usage: ./validate_sign_loan_tx <path/to/file.json>

Interactive prompts:

Please enter the path to your wallet file:
What is your wallet decryption key?

The tool asks the borrower to confirm:

  • Expected loan amount and asset.
  • Collateral amount and collateral asset.
  • Payment period.
  • Total number of payments.
  • Payment amount.
  • Grace period.
  • Maximum overdue value.
  • Loan start date.
  • Lender wallet address.

Validation performed before signing:

  • Confirms the JSON can be read and parsed.
  • Resolves lender and borrower addresses, including vanity inputs.
  • Confirms the loaded wallet matches the borrower address.
  • Confirms the borrower wallet short address is valid.
  • Rebuilds the unsigned loan transaction from the JSON fields.
  • Recomputes the loan hash.
  • Refuses to sign if the recomputed hash does not match the included hash.
  • Signs with the borrower wallet only after all prompts and hash validation pass.

Output:

The tool writes the fully signed transaction JSON under:

./transactions/<hash>.json

It also prints the signed JSON to the terminal.

If the user rejects any confirmation prompt, or if the hash does not match, the tool prints an error and does not sign.

verify_sign_swap_tx

Reviews, verifies, and signs a sender1-created swap transaction as sender2.

This tool is also covered in the swap documentation. In this validation document, the important point is that the tool protects the second signer. It reads the swap JSON, confirms the active wallet is sender2, asks sender2 to confirm the human-readable swap terms, rebuilds the unsigned swap, verifies the included hash, then writes a fully signed transaction JSON.

Usage:

verify_sign_swap_tx <path/to/file.json>

The current usage text printed by the tool is:

Usage:./sign_swap <path/to/file.json>

Interactive prompts:

Please enter the path to your wallet file:
What is your wallet decryption key?

The tool asks sender2 to confirm:

  • Amount and asset sender2 expects to receive.
  • Amount and asset sender2 expects to send.
  • Sender2 fee in the base coin.
  • Sender2 miner tip.

Validation performed before signing:

  • Confirms the JSON can be read and parsed.
  • Resolves sender1 and sender2 addresses, including vanity inputs.
  • Confirms the loaded wallet matches sender2.
  • Normalizes ticker names or accepts the base coin.
  • Rebuilds the unsigned swap transaction from the JSON fields.
  • Recomputes the swap hash.
  • Refuses to sign if the recomputed hash does not match the included hash.
  • Signs with the sender2 wallet only after all prompts and hash validation pass.

Output:

The tool writes the fully signed transaction JSON under:

./transactions/<hash>.json

It also prints the signed JSON to the terminal.

If the user rejects any confirmation prompt, or if the hash does not match, the tool prints an error and does not sign.