import "merklePath.scrypt"; struct BlockHeader { bytes version; Sha256 prevBlockHash; Sha256 merkleRoot; int time; bytes bits; int nonce; } library Blockchain { static const int BLOCK_HEIGHT_POS = 42; static function txInBlock(Sha256 txid, BlockHeader bh, Node[32] merkleProof, static const int depth) : bool { return (MerklePath.calcMerkleRoot(txid, merkleProof, depth) == bh.merkleRoot); } static function lastTxInBlock(Sha256 txid, BlockHeader bh, Node[32] merkleProof, static const int depth) : bool { bool last = true; Sha256 root = txid; loop (depth) : i { Node node = merkleProof[i]; if(node.pos != 0) { bool isDuplicate = node.hash == root; if(!isDuplicate && node.pos == 2) { last = false; } root = Sha256(node.pos == 1 ? hash256(node.hash + root) : hash256(root + node.hash)); } } return last && root == bh.merkleRoot; } static function isValidBlockHeader(BlockHeader bh, int blockchainTarget) : bool { int bhHash = Blockchain.blockHeaderHashAsInt(bh); int target = Blockchain.bits2Target(bh.bits); return bhHash <= target && target <= blockchainTarget; } static function verifyBlockHeader(BlockHeader bh) : bool { int bhHash = Blockchain.blockHeaderHashAsInt(bh); int target = Blockchain.bits2Target(bh.bits); return bhHash <= target; } static function isCoinbase(bytes tx) : bool { return (tx[4 : 5] == b'01' && tx[5 : 37] == b'0000000000000000000000000000000000000000000000000000000000000000' && tx[37 : 41] == b'ffffffff'); } static function blockHeight(BlockHeader bh, bytes coinbaseTx, Node[32] merkleProof, static const int depth) : int { require(Blockchain.txInBlock(Sha256(hash256(coinbaseTx)), bh, merkleProof, depth)); require(MerklePath.isCoinbase(merkleProof, depth)); return Blockchain.readBlockHeight(coinbaseTx); } static function readBlockHeight(bytes coinbaseTx) : int { return Utils.fromLEUnsigned(Utils.readVarint(coinbaseTx[42 : len(coinbaseTx)])); } static function bits2Target(bytes bits) : int { int exponent = Utils.fromLEUnsigned(bits[3 : len(bits)]); int coefficient = Utils.fromLEUnsigned(bits[0 : 3]); int n = 8 * (exponent - 3); return (coefficient << n); } static function serialize(BlockHeader bh) : bytes { return (bh.version + bh.prevBlockHash + bh.merkleRoot + Utils.toLEUnsigned(bh.time, 4) + bh.bits + Utils.toLEUnsigned(bh.nonce, 4)); } static function deserialize(bytes bh) : BlockHeader { return {bh[0 : 4], Sha256(bh[4 : 36]), Sha256(bh[36 : 68]), Utils.fromLEUnsigned(bh[68 : 72]), bh[72 : 76], Utils.fromLEUnsigned(bh[76 : 80])}; } static function blockHeaderHash(BlockHeader bh) : Sha256 { return hash256(Blockchain.serialize(bh)); } static function blockHeaderHashAsInt(BlockHeader bh) : int { return Utils.fromLEUnsigned(Blockchain.blockHeaderHash(bh)); } }