I have a giant hole in my understanding! I recently started using https://github.com/sebicas/bitcoin-sniffer which is a Python script that lets you connect to any node on the Bitcoin Network and triggers events: - new_block_event(block): Triggered when a Block is found - new_tx_event(tx): Triggered when a Transactions is found ----- On inspecting a new block I was quite surprised to find that the object does not include `block.height`! Then I found this question: http://bitcoin.stackexchange.com/questions/24309/is-block-height-always-sequential Quote: >Block height is by definition sequential in the sense that adjacent blocks will always have heights that differ by 1. But there is a chicken-and-egg problem: in order to compute the height, you have to have access to all the blocks in between the genesis block and the current one. (The height is not recorded in the block itself.) >There's also the issue that multiple blocks can have the same height, if they are on different branches of the chain. So just because you have one block at every height, doesn't mean you have all the blocks on the main chain; some of them might be on orphan branches. ---- So my Question is ----------------- How can i tell if the block is official and will not be replaced by a 'better' block? ----- I see that each block contains a previous block hash so my reasoning is that if a block was orphaned then the next blocks previous block hash would not be that blocks hash but another. But using that as a test to see If the last block became part of the network would put the check (time) back by one block... which is not realtime nor ideal The bitcoin-sniffer does have one curious function for a block message called **block.is_valid** at the end of the CBlock class: class CBlock(object): def __init__(self): self.nVersion = 1 self.hashPrevBlock = 0 self.hashMerkleRoot = 0 self.nTime = 0 self.nBits = 0 self.nNonce = 0 self.vtx = [] self.sha256 = None self.hash = None def deserialize(self, f): self.nVersion = struct.unpack("<i", f.read(4))[0] self.hashPrevBlock = deser_uint256(f) self.hashMerkleRoot = deser_uint256(f) self.nTime = struct.unpack("<I", f.read(4))[0] self.nBits = struct.unpack("<I", f.read(4))[0] self.nNonce = struct.unpack("<I", f.read(4))[0] self.vtx = deser_vector(f, CTransaction) def serialize(self): r = "" r += struct.pack("<i", self.nVersion) r += ser_uint256(self.hashPrevBlock) r += ser_uint256(self.hashMerkleRoot) r += struct.pack("<I", self.nTime) r += struct.pack("<I", self.nBits) r += struct.pack("<I", self.nNonce) r += ser_vector(self.vtx) return r def calc_sha256(self): if self.sha256 is None: r = "" r += struct.pack("<i", self.nVersion) r += ser_uint256(self.hashPrevBlock) r += ser_uint256(self.hashMerkleRoot) r += struct.pack("<I", self.nTime) r += struct.pack("<I", self.nBits) r += struct.pack("<I", self.nNonce) self.sha256 = uint256_from_str(hash256(r)) self.hash = hash256(r)[::-1].encode('hex_codec') def is_valid(self): self.calc_sha256() target = uint256_from_compact(self.nBits) if self.sha256 > target: return False hashes = [] for tx in self.vtx: if not tx.is_valid(): return False tx.calc_sha256() hashes.append(ser_uint256(tx.sha256)) while len(hashes) > 1: newhashes = [] for i in xrange(0, len(hashes), 2): i2 = min(i+1, len(hashes)-1) newhashes.append(hash256(hashes[i] + hashes[i2])) hashes = newhashes if uint256_from_str(hashes[0]) != self.hashMerkleRoot: return False return True def __repr__(self): return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx)) The function is *'way-over-my-head'* to be honest but it looks like it might be trying to determine weather the block can be trusted (as in; not tampered with as its querying the `hashMerkleRoot` which is one way) but, I'm not knowledgeable enough to to tell for sure if the `is_valid` is doing more like (determining that the block is official) The last thing I want to do is: 1. push a tx to the network 2. listen to `new_tx_event(tx)` get my tx hash 3. listen to `new_block_event(block)` find my has accepted in the block 4. start to confirm payment counting new blocks as confirmations 5. find out later that the block got replaced/became orphaned Your thoughts?