When verifying BEEF structures, it's necessary to ensure that all transactions are well-anchored: this is to say, that they come from inputs in the honest chain. The SDK doesn't ship with a headers client, but this guide shows an example of how to use it with Pulse: a popular client suitable for a wide range of use-cases.
Pre-requisites
As stated in the README, you will need to be running a Pulse instance. Get it up and running, and configure a level of authentication appropriate for your use-case:
docker pull bsvb/block-headers-service
docker run bsvb/block-headers-service:latest
Building our Client
The SDK's ChainTracker interface defines the required structure for our implementation, as follows:
class ChainTracker(ABC):
"""
The Chain Tracker is responsible for verifying the validity of a given Merkle root
for a specific block height within the blockchain.
Chain Trackers ensure the integrity of the blockchain by
validating new headers against the chain's history. They use accumulated
proof-of-work and protocol adherence as metrics to assess the legitimacy of blocks.
"""
@abstractmethod
async def is_valid_root_for_height(self, root: str, height: int) -> bool:
"""
Verify the validity of a Merkle root for a given block height.
:param root: The Merkle root to verify.
:param height: The block height to verify against.
:return: A boolean indicating if the Merkle root is valid for the specified block height.
"""
pass
Given an array of merkle roots and corresponding block heights, we return a boolean indicating whether they're all valid.
We can plug in the Block Header Service API with appropriate HTTP handling logic as follows:
Now, we can use our WhatsOnChainTracker as a ChainTracker when calling the Transaction object's .verify() method. You can see an example in the BEEF verification guide.
This provides the ability to ensure that a transaction is well-anchored.