UNPKG

@atomiqlabs/chain-starknet

Version:
143 lines (129 loc) 4.36 kB
import {BtcHeader} from "@atomiqlabs/base"; import {Buffer} from "buffer"; import {BigNumberish} from "starknet"; import {toHex, u32ArrayToBuffer, u32ReverseEndianness} from "../../../utils/Utils"; import {sha256} from "@noble/hashes/sha2"; export type StarknetBtcHeaderType = { reversed_version: BigNumberish; previous_blockhash: BigNumberish[]; merkle_root: BigNumberish[]; reversed_timestamp: BigNumberish; nbits: BigNumberish; nonce: BigNumberish; hash?: Buffer } /** * Representing a new bitcoin blockheader struct to be submitted to the Starknet BTC relay smart contract * * @category BTC Relay */ export class StarknetBtcHeader implements BtcHeader { private readonly reversed_version: number; private readonly previous_blockhash: number[]; private readonly merkle_root: number[]; private readonly reversed_timestamp: number; private readonly nbits: number; private readonly nonce: number; private readonly hash?: Buffer; /** * Constructs the bitcoin blockheader from a struct as returned by the starknet.js lib * * @param obj Struct as returned by the starknet.js lib * * @internal */ constructor(obj: StarknetBtcHeaderType) { this.reversed_version = Number(obj.reversed_version); this.previous_blockhash = obj.previous_blockhash.map(val => Number(val)); this.merkle_root = obj.merkle_root.map(val => Number(val)); this.reversed_timestamp = Number(obj.reversed_timestamp); this.nbits = Number(obj.nbits); this.nonce = Number(obj.nonce); this.hash = obj.hash; } /** * @inheritDoc */ getMerkleRoot(): Buffer { return u32ArrayToBuffer(this.merkle_root); } /** * @inheritDoc */ getNbits(): number { return u32ReverseEndianness(this.nbits); } /** * @inheritDoc */ getNonce(): number { return u32ReverseEndianness(this.nonce); } /** * @inheritDoc */ getReversedPrevBlockhash(): Buffer { return u32ArrayToBuffer(this.previous_blockhash); } /** * @inheritDoc */ getTimestamp(): number { return u32ReverseEndianness(this.reversed_timestamp); } /** * @inheritDoc */ getVersion(): number { return u32ReverseEndianness(this.reversed_version); } /** * @inheritDoc */ getHash(): Buffer { if(this.hash!=null) return this.hash; const buffer = Buffer.alloc(80); buffer.writeUInt32BE(this.reversed_version, 0); u32ArrayToBuffer(this.previous_blockhash).copy(buffer, 4); u32ArrayToBuffer(this.merkle_root).copy(buffer, 36); buffer.writeUInt32BE(this.reversed_timestamp, 68); buffer.writeUInt32BE(this.nbits, 72); buffer.writeUInt32BE(this.nonce, 76); return Buffer.from(sha256(sha256(buffer))); } /** * Serializes the bitcoin blockheader struct to an array of felt252 of length 20 */ serialize(): BigNumberish[] { return [ this.reversed_version, ...this.previous_blockhash, ...this.merkle_root, this.reversed_timestamp, this.nbits, this.nonce ]; } /** * Deserializes the store bitcoin blockheader from its felt252 array representation * * @param span felt252 array encoding the stored blockheader, has to be at least 20 felts long */ static fromSerializedFeltArray(span: BigNumberish[]): StarknetBtcHeader { if(span.length<20) throw new Error("Invalid serialized data size!"); const reversed_version = toHex(span.shift()!); const previous_blockhash = span.splice(0, 8).map(val => toHex(val)); const merkle_root = span.splice(0, 8).map(val => toHex(val)); const reversed_timestamp = toHex(span.shift()!); const nbits = toHex(span.shift()!); const nonce = toHex(span.shift()!); return new StarknetBtcHeader({ reversed_version, previous_blockhash, merkle_root, reversed_timestamp, nbits, nonce }); } }