package bitcoinml

  1. Overview
  2. Docs

Source file block.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
open Stdint;;
open Bitstring;;
open Bytes;;
open Varint;;
open Hash;;

module Header = struct
	type t = {
		hash		: Hash.t;
		version		: int32;
		prev_block	: Hash.t;
		merkle_root : Merkle.t;
		time		: float;
		bits		: string;
		nonce		: uint32;
	};;

	let serialize h =
		let btime = Bytes.create 4 in
		Uint32.to_bytes_little_endian (Uint32.of_float h.time) btime 0;
		let bnonce = Bytes.create 4 in
		Uint32.to_bytes_little_endian h.nonce bnonce 0;
		let%bitstring bs = {|
			h.version 							: 4*8 : littleendian;
			Hash.to_bin h.prev_block			: 32*8: string;
			Hash.to_bin h.merkle_root			: 32*8: string;
			to_string btime				: 32 : string;
			Hash.to_bin_norev h.bits			: 32 : string;
			to_string bnonce				: 32 : string
		|} in Bitstring.string_of_bitstring bs
	;;

	let check_target h =
		let calc_target b =
			let b = Hash.to_bin_norev b in 
			let exp = (String.get b 3 |> Char.code) - 3 in
			let mantissa = (String.make 1 @@ String.get b 2) ^ (String.make 1 @@ String.get b 1) ^ (String.make 1 @@ String.get b 0) in
			let n = if 32 - exp - 3 > 0 then
					String.make (32 - exp - 3) (Char.chr 0) ^ mantissa ^ String.make exp (Char.chr 0) 
				else
					mantissa ^ String.make exp (Char.chr 0)
			in
			Hash.of_bin_norev n
		in
		let rec check h t = match String.length h with
		| 0 -> true
		| n ->
			let fh = String.get h 0 in
			let ft = String.get t 0 in
			let resth = if n = 1 then "" else String.sub h 1 (n-1) in
			let restt = if n = 1 then "" else String.sub t 1 (n-1) in
			match (fh, ft) with
			| '0', '0' -> check resth restt 
			| '0', b when b <> '0' -> true
			| a, '0' when a <> '0' -> false
			| a, b when a = b -> check resth restt
			| a, b -> 
				let a' = Scanf.sscanf (String.make 1 a) "%1x" (fun i -> i) in
				let b' = Scanf.sscanf (String.make 1 b) "%1x" (fun i -> i) in
				if a' > b' then false else true
		in check h.hash @@ calc_target h.bits
	;;

	let parse data =
		let bdata = bitstring_of_string data in
		match%bitstring bdata with
		| {|
			version 	: 4*8 : littleendian;
			prev_block	: 32*8: string;
			merkle_root	: 32*8: string;
			time		: 32 : string;
			bits		: 32 : string;
			nonce		: 32 : string
		|} ->
			let hash = Hash.of_bin (hash256 data) in
			Some ({
				hash			= hash;
				version			= version;
				prev_block		= Hash.of_bin prev_block;
				merkle_root		= Hash.of_bin merkle_root;
				time			= Uint32.to_float (Uint32.of_bytes_little_endian (of_string time) 0);
				bits			= Hash.of_bin_norev bits;
				nonce			= Uint32.of_bytes_little_endian (of_string nonce) 0;
			})
		| {| _ |} -> None
	;;
end

type t = {
	header	: Header.t;
	txs			: Tx.t list;
	size		: int;
};;




let parse data =
	let header = Header.parse (String.sub data 0 80) in
	match header with
	| None -> None
	| Some (header) ->
		let bdata = bitstring_of_string  (String.sub data 80 ((String.length data) - 80)) in
		let txn, rest' = parse_varint bdata in
		let txs = Tx.parse_all (string_of_bitstring rest') (Uint64.to_int txn) in
		match txs with
		| Some (txs) -> Some ({ header= header; txs= List.rev txs; size= String.length data })
		| None -> None
;;

let parse_legacy data =
	let header = Header.parse (String.sub data 0 80) in
	match header with
	| None -> None
	| Some (header) ->	
		let bdata = bitstring_of_string  (String.sub data 80 ((String.length data) - 80)) in
		let txn, rest' = parse_varint bdata in
		let txs = Tx.parse_all_legacy (string_of_bitstring rest') (Uint64.to_int txn) in
		match txs with
		| Some (txs) -> Some ({ 
			header= header; 
			txs= List.rev txs; 
			size= 80 + Varint.encoding_length txn + List.fold_left (fun a x -> a + x.Tx.size) 0 txs;
		})
		| None -> None
;;



let serialize block =
	let d = Header.serialize (block.header) in
	let d = String.concat "" [d; string_of_bitstring (bitstring_of_varint (Int64.of_int (List.length block.txs)))] in
	String.concat "" [d; Tx.serialize_all block.txs]
;;
OCaml

Innovation. Community. Security.