Functions: Storage and Verification

initialize

Initializes BTC-Relay with the first Bitcoin block to be tracked and initializes all data structures (see Data Model).

Note

BTC-Relay does not have to be initialized with Bitcoin’s genesis block! The first block to be tracked can be selected freely.

Warning

Caution when setting the first block in BTC-Relay: only succeeding blocks can be submitted and predecessors will be rejected!

Specification

Function Signature

initialize(blockHeaderBytes, blockHeight)

Parameters

  • relayer: the account submitting the block
  • blockHeaderBytes: 80 byte raw Bitcoin block header
  • blockHeight: integer Bitcoin block height of the submitted block header

Events

  • Initialized(blockHeight, blockHash, relayer): if the first block header was stored successfully, emit an event with the stored block’s height (blockHeight) and the (PoW) block hash (blockHash).

Errors

  • ERR_ALREADY_INITIALIZED = "Already initialized": return error if this function is called after BTC-Relay has already been initialized.

Preconditions

  • This is the first time this function is called, i.e., when BTC-Relay is being deployed.

Function sequence

  1. Check if initialize is called for the first time. Return ERR_ALREADY_INITIALIZED if BTC-Relay has already been initialized.

  2. Parse blockHeaderBytes, extracting the merkleRoot (extractMerkleRoot), timestamp (extractTimestamp) and target (extractNBits and nBitsToTarget) from blockHeaderBytes, and compute the block hash (hashCurrentBlock) using sha256d (passing blockHeaderBytes as parameter).

  3. Create a new BlockChain entry in Chains:

    • chainId =incrementChainCounter
    • startHeight = blockHeight
    • maxHeight = blockHeight
    • noData = Vec::new()
    • invalid = Vec::new()
    • Insert hashCurrentBlock in the chain mapping using blockHeight as key.
  4. Insert a pointer to BlockChain into ChainsIndex using chainId as key.

  5. Store a new RichBlockHeader struct containing merkleRoot, blockHeight, timestamp, target, and a pointer (chainRef) to the BlockChain struct - as associated with this block header - in BlockHeaders, using hashCurrentBlock as key.

  6. Set BestBlock = hashCurrentBlock and BestBlockHeight = blockHeight.

  7. Emit a Initialized event using height and hashCurrentBlock as input.

Warning

Attention: the Bitcoin block header submitted to initialize must be in the Bitcoin main chain - this must be checked outside of the BTC Bridge before making this function call! A wrong initialization will cause the entire BTC Bridge to fail, since verification requires that all submitted blocks must (indirectly) point to the initialized block (i.e., have it as ancestor, just like the actual Bitcoin genesis block).

storeBlockHeader

Method to submit block headers to the BTC-Relay. This function calls verifyBlockHeader providing the 80 bytes Bitcoin block header as input, and, if the latter returns True, extracts from the block header and stores the hash, height and Merkle tree root of the given block header in BlockHeaders. If the block header extends an existing BlockChain entry in Chains, it appends the block hash to the chains mapping and increments the maxHeight. Otherwise, a new Blockchain entry is created.

Specification

Function Signature

storeBlockHeader(relayer, blockHeaderBytes)

Parameters

  • relayer: the account submitting the block
  • blockHeaderBytes: 80 byte raw Bitcoin block header.

Events

  • StoreMainChainHeader(blockHeight, blockHash, relayer): if the block header was successful appended to the currently longest chain (main chain) emit an event with the stored block’s height (blockHeight) and the (PoW) block hash (blockHash).
  • StoreForkHeader(forkId, blockHeight, blockHash, relayer): if the block header was successful appended to a new or existing fork, emit an event with the block height (blockHeight) and the (PoW) block hash (blockHash).

Preconditions

  • The BTC Bridge status must not be set to SHUTDOWN: 3.

Warning

The BTC-Relay does not necessarily have the same view of the Bitcoin blockchain as the user’s local Bitcoin client. This can happen if (i) the BTC-Relay is under attack, (ii) the BTC-Relay is out of sync, or, similarly, (iii) if the user’s local Bitcoin client is under attack or out of sync (see Security Analysis).

Note

The 80 bytes block header can be retrieved from the bitcoin-rpc client by calling the getBlock and setting verbosity to 0 (getBlock <blockHash> 0).

Function sequence

  1. Call verifyBlockHeader passing blockHeaderBytes as function parameter. If this call returns an error , then abort and return the raised error. If successful, this call returns a parsed BlockHeader (BlockHeader) struct.

  2. Determine which BlockChain entry in Chains this block header is extending, or if it is a new fork and hence a new BlockChain entry needs to be created. For this, get the prevBlockHeader (RichBlockHeader) stored in BlockHeaders with BlockHeader.hashPrevBlock and use prevBlockHeader.chainRef to lookup the associated BlockChain struct in ChainsIndex. Then, check if the prevBlockHeader.blockHeight (as referenced by hashPrevBlock) is equal to BlockChain.maxHeight.

    1. If not equal (can only be less in this case), then the current submission is creating a new fork.

    i ) Create a new BlockChain struct, setting BlockChain.startHeight = RichBlockHeader.blockHeight (as referenced in hashPrevBlock), BlockChain.maxHeight = RichBlockHeader.blockHeight + 1 (as referenced in hashPrevBlock), and appending hashCurrentBlock (compute the block hash using sha256d, passing blockHeaderBytes as parameter) to the (currently empty) BlockChain.chain mapping.

    ii ) Set BlockChain.chainId = incrementChainCounter.

    iii ) Insert the new BlockChain into Chains.

    iv ) Insert the new BlockChain into ChainsIndex using BlockChain.chainId as key.

  1. Otherwise, if equal, then the current submission is extending the BlockChain referenced by RichBlockHeader.chainRef (as per``hashPrevBlock``).

i ) Append the hashCurrentBlock to the chain map in BlockChain and increment maxHeight

ii ) Check if a blockchain reorganization is necessary. For this, call checkAndDoReorg passing the pointer to BlockChain as parameter.

  1. Check if BlockChain is the main chain, i.e. check if chainId == MAIN_CHAIN_ID.
    1. If BlockChain is not the main chain (chainId =/= MAIN_CHAIN_ID) and BlockChain.maxHeight > nextBestForkHeight set nextBestForkHeight = BlockChain.maxHeight.
    2. If BlockChain is the main chain (chainId == MAIN_CHAIN_ID) set BestBlock = hashCurrentBlock and BestBlockHeight = BlockChain.maxHeight.
  2. Create a new RichBlockHeader and initalize as follows:
  • RichBlockHeader.blockHeight = prevBlock.blockHeight + 1,
  • RichBlockHeader.chainRef = BlockChain.chainId,
  • RichBlockHeader.merkleRoot = BlockHeader.merkleRoot,
  • RichBlockHeader.target = BlockHeader.target,
  • RichBlockHeader.timestamp = BlockHeader.timestamp,
  • RichBlockHeader.hashPrevBlock = BlockHeader.hashPrevBlock
  1. Insert RichBlockHeader into BlockHeaders using hashCurrentBlock as key.
  2. Emit event.
    1. If submission was to main chain (BlockChain with chainId == MAIN_CHAIN_ID), emit StoreMainChainBlockHeader event using height and hashCurrentBlock as input (StoreMainChainHeader(height, hashCurrentBlock)).
    2. If submission was to another BlockChain entry (new or existing), emit StoreForkHeader(height, hashCurrentBlock).
storeBlockHeader sequence diagram

Sequence diagram showing the function sequence of storeBlockHeader.

checkAndDoReorg

This function is called from storeBlockHeader and checks if a block header submission resulted in a chain reorganization. Updates the ordering in / re-balances Chains if necessary.

Specification

Function Signature

checkAndDoReorg(fork)

Parameters

  • &fork: pointer to a BlockChain entry in Chains.

Events

  • ChainReorg(newChainTip, blockHeight, forkDepth): if the submitted block header on a fork results in a reorganization (fork longer than current main chain), emit an event with the block hash of the new highest block (newChainTip), the new maximum block height (blockHeight) and the depth of the fork (forkDepth).

Function Sequence

  1. Check if the ordering of the BlockChain entry needs updating. For this, check the maxHeight of the “next-highest” BlockChain (parent in heap or predecessor in sorted linked list) in Chains.
  1. If fork is the top-level element, i.e., the main chain, do nothing.
  2. Else if the “next-highest” entry has a lower maxHeight, update ordering by switching positions - continue, until reaching the “top” of the Chains data structure or a BlockChain entry with a higher maxHeight.
  1. If ordering was updated, check if the top-level element in the Chains data structure changed (i.e., is no longer the main chain defined by MAIN_CHAIN_ID). If this is the case:
  1. Retrieve the main chain BlockChain entry (mainChain) from ChainsIndex using MAIN_CHAIN_ID
  2. Check if the maxHeight of the new top-level BlockChain exceeds mainChain.maxHeight by at least STABLE_BITCOIN_CONFIRMATIONS. If true, continue. If false, return (no chain reorg needs to be executed yet).
  1. Create a new empty BlockChain (forkedMainChain) struct and initalize with:
  • forkedMainChain.chainId = incrementChainCounter,
  • forkedMainChain.chain = HashMap::new()
  • forkedMainChain.startHeight = fork.startHeight,
  • forkedMainChain.maxHeight = mainChain.maxHeight
  • forkedMainChain.noData = Vec::new()
  • forkedMainChain.invalid = Vec::new()
  1. Loop: starting from fork.startHeight as currHeight until fork.maxHeight:

i ) Set forkedMainChain.chain[currHeight] = mainChain.chain[currHeight] (overwrite the forked out main chain blocks with blocks in the fork).

ii ) Get the RichBlockHeader for the new mainChain.chain[currHeight] and update its chainRef to point to mainChain.

iii ) Set forkedMainChain.chain[currHeight] = fork.chain[currHeight] (write forked main chain blocks to new BlockChain entry to be tracked as an ongoing fork).

iv ) Get the RichBlockHeader for the new forkedMainChain.chain[currHeight] and update its chainRef to point to forkedMainChain.

v ) If currHeight > mainChain.maxHeight set mainChain.maxHeight = currHeight.

  1. For each block height in fork.noData and fork.invalid: add the block height to mainChain.noData and mainChain.noData respectively.
  2. Update BestBlockHeight = mainChain.maxHeight and BestBlock = mainChain.chain[mainChain.maxHeight] (nextBestForkHeight updated in storeBlockHeader).
  1. Check that noData or invalid are both empty in mainChain. If this is the case, check if we need to update the BTC Bridge state.

i ) If noData or invalid are both empty and Errors in Security Analysis contains NO_DATA_BTC_RELAY or INVALID_BTC_RELAY call recoverFromBTCRelayFailure to recover the BTC Bridge from the BTC-Relay related error.

ii ) If BridgeStatus is set to RUNNING and either noData or invalid are not empty in the new main chain BlockChain entry: update BridgeStatus to ERROR and append NO_DATA_BTC_RELAY or INVALID_BTC_RELAY (depending on which of invalid and noData lists was not empty) to the Errors list.

  1. Remove fork from Chains.
  2. Emit a ChainReorg(newChainTip, blockHeight, forkDepth), where newChainTip is the new BestBlock, blockHeight is the new BestBlockHeight, and forkDepth is the depth of the fork (fork.maxHeight - fork.startHeight).

Note

We may want to track the mainChain identifier separately for quicker access (same main chain updated in case of forks).

verifyBlockHeader

The verifyBlockHeader function parses and verifies Bitcoin block headers. If all checks are successful, returns a BlockHeader representation of the 80 byte raw block header given as input.

Note

This function does not check whether the submitted block header extends the main chain or a fork. This check is performed in storeBlockHeader.

Specification

Function Signature

verifyBlockHeader(blockHeaderBytes)

Parameters

  • blockHeaderBytes: 80 byte raw Bitcoin block header.

Returns

  • BlockHeader: if all checks pass successfully, return a parsed BlockHeader.

Errors

  • ERR_DUPLICATE_BLOCK = "Block already stored": return error if the submitted block header is already stored in BTC-Relay (duplicate PoW blockHash).
  • ERR_PREV_BLOCK = "Previous block hash not found": return error if the submitted block does not reference an already stored block header as predecessor (via prevBlockHash).
  • ERR_LOW_DIFF = "PoW hash does not meet difficulty target of header": return error when the header’s blockHash does not meet the target specified in the block header.
  • ERR_DIFF_TARGET_HEADER = "Incorrect difficulty target specified in block header": return error if the target specified in the block header is incorrect for its block height (difficulty re-target not executed).

Function Sequence

  1. Call parseBlockHeader passing blockHeaderBytes as parameter to parse the block header. If this call returns an error, abort and return the error. If successful, parseBlockHeader returns a parsed BlockHeader (BlockHeader) struct.
  2. Compute hashCurrentBlock, the double SHA256 hash over the 80 bytes block header, using sha256d (passing blockHeaderBytes as parameter).
  3. Check that the block header is not yet stored in BTC-Relay (hashCurrentBlock must not yet be in BlockHeaders). Return ERR_DUPLICATE_BLOCK otherwise.
  4. Get the RichBlockHeader (prevBlock) referenced by the submitted block header via BlockHeader.hashPrevBlock. Return ERR_PREV_BLOCK if no such entry was found.
  5. Check that the Proof-of-Work hash (hashCurrentBlock) is below the BlockHeader.target. Return ERR_LOW_DIFF otherwise.
  6. Check that the BlockHeader.target is correct by calling checkCorrectTarget passing BlockHeader.hashPrevBlock, prevBlock.blockHeight and BlockHeader.target as parameters (as per Bitcoin’s difficulty adjustment mechanism, see here). If this call returns False, return ERR_DIFF_TARGET_HEADER.
  7. Return BlockHeader
verifyBlockHeader sequence diagram

Sequence diagram showing the function sequence of verifyBlockHeader.

verifyTransactionInclusion

The verifyTransactionInclusion function is one of the core components of the BTC-Relay: this function checks if a given transaction was indeed included in a given block (as stored in BlockHeaders and tracked by Chains), by reconstructing the Merkle tree root (given a Merkle proof). Also checks if sufficient confirmations have passed since the inclusion of the transaction (considering the current state of the BTC-Relay Chains).

Specification

Function Signature

verifyTransactionInclusion(txId, merkleProof, confirmations, insecure)

Parameters

  • txId: 32 byte hash identifier of the transaction.
  • merkleProof: Merkle tree path (concatenated LE sha256 hashes, dynamic sized).
  • confirmations: integer number of confirmation required.

Note

The Merkle proof for a Bitcoin transaction can be retrieved using the bitcoin-rpc gettxoutproof method and dropping the first 170 characters. The Merkle proof thereby consists of a list of SHA256 hashes, as well as an indicator in which order the hash concatenation is to be applied (left or right).

Returns

  • True: if the given txId appears in at the position specified by txIndex in the transaction Merkle tree of the block at height blockHeight and sufficient confirmations have passed since inclusion.
  • Error otherwise.

Events

  • VerifyTransaction(txId, txBlockHeight, confirmations): if verification was successful, emit an event specifying the txId, the blockHeight and the requested number of confirmations.

Errors

  • ERR_SHUTDOWN = "BTC Bridge has shut down": the BTC Bridge has been shutdown by a manual intervention of the Governance Mechanism.
  • ERR_MALFORMED_TXID = "Malformed transaction identifier": return error if the transaction identifier (txId) is malformed.
  • ERR_CONFIRMATIONS = "Transaction has less confirmations than requested": return error if the block in which the transaction specified by txId was included has less confirmations than requested.
  • ERR_INVALID_MERKLE_PROOF = "Invalid Merkle Proof": return error if the Merkle proof is malformed or fails verification (does not hash to Merkle root).
  • ERR_ONGOING_FORK = "Verification disabled due to ongoing fork": return error if the mainChain is not at least STABLE_BITCOIN_CONFIRMATIONS ahead of the next best fork.

Preconditions

  • The BTC Bridge status must not be set to SHUTDOWN: 3. If SHUTDOWN is set, all transaction verification is disabled.

Function Sequence

  1. Check that txId is 32 bytes long. Return ERR_MALFORMED_TXID error if this check fails.
  2. Check that the current BestBlockHeight exceeds txBlockHeight by the requested confirmations. Return ERR_CONFIRMATIONS if this check fails.
  1. If insecure == True, check against user-defined confirmations only
  2. If insecure == True, check against max(confirmations, STABLE_BITCOIN_CONFIRMATIONS).
  1. Check if the Bitcoin block was stored for a sufficient number of blocks (on the shard) to ensure that staked relayers had the time to flag the block as potentially invalid. Check performed against STABLE_PARACHAIN_CONFIRMATIONS.
  2. Extract the block header from BlockHeaders using the blockHash tracked in Chains at the passed txBlockHeight.
  3. Check that the first 32 bytes of merkleProof are equal to the txId and the last 32 bytes are equal to the merkleRoot of the specified block header. Also check that the merkleProof size is either exactly 32 bytes, or is 64 bytes or more and a power of 2. Return ERR_INVALID_MERKLE_PROOF if one of these checks fails.
  4. Call computeMerkle passing txId, txIndex and merkleProof as parameters.
  1. If this call returns the merkleRoot, emit a VerifyTransaction(txId, txBlockHeight, confirmations) event and return True.
  2. Otherwise return ERR_INVALID_MERKLE_PROOF.
verifyTransactionInclusion sequence diagram

The steps to verify a transaction in the verifyTransactionInclusion function.

validateTransaction

Given a raw Bitcoin transaction, this function

  1. Parses and extracts
    1. the value and recipient address of the Payment UTXO,
    2. [Optionally] the OP_RETURN value of the Data UTXO.
  2. Validates the extracted values against the function parameters.

Note

See Bitcoin Data Model for more details on the transaction structure, and Accepted Bitcoin Transaction Format for the transaction format of Bitcoin transactions validated in this function.

Specification

Function Signature

validateTransaction(rawTx, paymentValue, recipientBtcAddress, opReturnId)

Parameters

  • rawTx: raw Bitcoin transaction including the transaction inputs and outputs.
  • paymentValue: integer value of BTC sent in the (first) Payment UTXO of transaction.
  • recipientBtcAddress: 20 byte Bitcoin address of recipient of the BTC in the (first) Payment UTXO.
  • opReturnId: [Optional] 32 byte hash identifier expected in OP_RETURN (see Replay Attacks).

Returns

  • True: if the transaction was successfully parsed and validation of the passed values was correct.
  • Error otherwise.

Events

  • ValidateTransaction(txId, paymentValue, recipientBtcAddress, opReturnId): if parsing and validation was successful, emit an event specifying the txId, the paymentValue, the recipientBtcAddress and the opReturnId.

Errors

  • ERR_INSUFFICIENT_VALUE = "Value of payment below requested amount": return error the value of the (first) Payment UTXO is lower than paymentValue.
  • ERR_TX_FORMAT = "Transaction has incorrect format": return error if the transaction has an incorrect format (see Accepted Bitcoin Transaction Format).
  • ERR_WRONG_RECIPIENT = "Incorrect recipient Bitcoin address": return error if the recipient specified in the (first) Payment UTXO does not match the given recipientBtcAddress.
  • ERR_INVALID_OPRETURN = "Incorrect identifier in OP_RETURN field": return error if the OP_RETURN field of the (second) Data UTXO does not match the given opReturnId.

Preconditions

  • The BTC Bridge status must not be set to SHUTDOWN: 3. If SHUTDOWN is set, all transaction validation is disabled.

Function Sequence

See the raw Transaction Format section in the Bitcoin Developer Reference for a full specification of Bitcoin’s transaction format (and how to extract inputs, outputs etc. from the raw transaction format).

  1. Extract the outputs from rawTx using extractOutputs.
  1. Check that the transaction (rawTx) has at least 2 outputs. One output (Payment UTXO) must be a P2PKH or P2WPKH output. Another output (Data UTXO) must be an OP_RETURN output. Raise ERR_TX_FORMAT if this check fails.
  1. Extract the value of the Payment UTXO using extractOutputValue and check that it is equal (or greater) than paymentValue. Return ERR_INSUFFICIENT_VALUE if this check fails.
  2. Extract the Bitcoin address specified as recipient in the Payment UTXO using extractOutputAddress and check that it matches recipientBtcAddress. Return ERR_WRONG_RECIPIENT if this check fails, or the error returned by extractOutputAddress (if the output was malformed).
  3. Extract the OP_RETURN value from the Data UTXO using extractOPRETURN and check that it matches opReturnId. Return ERR_INVALID_OPRETURN error if this check fails, or the error returned by extractOPRETURN (if the output was malformed).

verifyAndValidateTransaction

The verifyAndValidateTransaction function is a wrapper around the verifyTransactionInclusion and the validateTransaction functions. It adds an additional check to verify that the validated transaction is the one included in the specified block.

Specification

Function Signature

verifyAndValidateTransaction(merkleProof, confirmations, rawTx, paymentValue, recipientBtcAddress, opReturnId)

Parameters

  • txId: 32 byte hash identifier of the transaction.
  • merkleProof: Merkle tree path (concatenated LE sha256 hashes, dynamic sized).
  • confirmations: integer number of confirmation required.
  • rawTx: raw Bitcoin transaction including the transaction inputs and outputs.
  • paymentValue: integer value of BTC sent in the (first) Payment UTXO of transaction.
  • recipientBtcAddress: 20 byte Bitcoin address of recipient of the BTC in the (first) Payment UTXO.
  • opReturnId: [Optional] 32 byte hash identifier expected in OP_RETURN (see Replay Attacks).

Returns

  • True: If the same transaction has been verified and validated.
  • Error otherwise.

Function Sequence

  1. Parse the rawTx to get the tx id.
  2. Call verifyTransactionInclusion with the applicable parameters.
  3. Call validateTransaction with the applicable parameters.

flagBlockError

Flags tracked Bitcoin block headers when Staked Relayers report and agree on a NO_DATA_BTC_RELAY or INVALID_BTC_RELAY failure.

Attention

This function does not validate the Staked Relayers accusation. Instead, it is put up to a majority vote among all Staked Relayers in the form of a

Note

This function can only be called from the Security module of ONEBTC, after Staked Relayers have achieved a majority vote on a BTC Bridge status update indicating a BTC-Relay failure.

Specification

Function Signature

flagBlockError(blockHash, errors)

Parameters

  • blockHash: SHA256 block hash of the block containing the error.
  • errors: list of ErrorCode entries which are to be flagged for the block with the given blockHash. Can be “NO_DATA_BTC_RELAY” or “INVALID_BTC_RELAY”.

Events

  • FlagBTCBlockError(blockHash, chainId, errors) - emits an event indicating that a Bitcoin block hash (identified blockHash) in a BlockChain entry (chainId) was flagged with errors (errors list of ErrorCode entries).

Errors

  • ERR_UNKNOWN_ERRORCODE = "The reported error code is unknown": The reported ErrorCode can only be NO_DATA_BTC_RELAY or INVALID_BTC_RELAY.
  • ERR_BLOCK_NOT_FOUND  = "No Bitcoin block header found with the given block hash": No RichBlockHeader entry exists with the given block hash.
  • ERR_ALREADY_REPORTED = "This error has already been reported for the given block hash and is pending confirmation": The error reported for the given block hash is currently pending a vote by Staked Relayers.

Function Sequence

  1. Check if errors contains NO_DATA_BTC_RELAY or INVALID_BTC_RELAY. If neither match, return ERR_UNKNOWN_ERRORCODE.
  2. Retrieve the RichBlockHeader entry from BlockHeaders using blockHash. Return ERR_BLOCK_NOT_FOUND if no block header can be found.
  3. Retrieve the BlockChain entry for the given RichBlockHeader using ChainsIndex for lookup with the block header’s chainRef as key.
  4. Flag errors in the BlockChain entry:
    1. If errors contains NO_DATA_BTC_RELAY, append the RichBlockHeader.blockHeight to BlockChain.noData
    2. If errors contains INVALID_BTC_RELAY, append the RichBlockHeader.blockHeight to BlockChain.invalid .
  5. Emit FlagBTCBlockError(blockHash, chainId, errors) event, with the given blockHash, the chainId of the flagged BlockChain entry and the given errors as parameters.
  6. Return

clearBlockError

Clears ErrorCode entries given as parameters from the status of a RichBlockHeader. Can be NO_DATA_BTC_RELAY or INVALID_BTC_RELAY failure.

Note

This function can only be called from the Security module of ONEBTC, after Staked Relayers have achieved a majority vote on a BTC Bridge status update indicating that a RichBlockHeader entry no longer has the specified errors.

Specification

Function Signature

flagBlockError(blockHash, errors)

Parameters

  • blockHash: SHA256 block hash of the block containing the error.
  • errors: list of ErrorCode entries which are to be cleared from the block with the given blockHash. Can be NO_DATA_BTC_RELAY or INVALID_BTC_RELAY.

Events

  • ClearBlockError(blockHash, chainId, errors) - emits an event indicating that a Bitcoin block hash (identified blockHash) in a BlockChain entry (chainId) was cleared from the given errors (errors list of ErrorCode entries).

Errors

  • ERR_UNKNOWN_ERRORCODE = "The reported error code is unknown": The reported ErrorCode can only be NO_DATA_BTC_RELAY or INVALID_BTC_RELAY.
  • ERR_BLOCK_NOT_FOUND  = "No Bitcoin block header found with the given block hash": No RichBlockHeader entry exists with the given block hash.
  • ERR_ALREADY_REPORTED = "This error has already been reported for the given block hash and is pending confirmation": The error reported for the given block hash is currently pending a vote by Staked Relayers.

Function Sequence

  1. Check if errors contains NO_DATA_BTC_RELAY or INVALID_BTC_RELAY. If neither match, return ERR_UNKNOWN_ERRORCODE.
  2. Retrieve the RichBlockHeader entry from BlockHeaders using blockHash. Return ERR_BLOCK_NOT_FOUND if no block header can be found.
  3. Retrieve the BlockChain entry for the given RichBlockHeader using ChainsIndex for lookup with the block header’s chainRef as key.
  4. Un-flag error codes in the BlockChain entry.
    1. If errors contains NO_DATA_BTC_RELAY: remove RichBlockHeader.blockHeight from BlockChain.noData
    2. If errors contains INVALID_BTC_RELAY: remove RichBlockHeader.blockHeight from BlockChain.invalid
  5. Emit ClearBlockError(blockHash, chainId, errors) event, with the given blockHash, the chainId of the flagged BlockChain entry and the given errors as parameters.
  6. Return