-
Notifications
You must be signed in to change notification settings - Fork 0
/
scrape-blockexplorer.coffee
98 lines (71 loc) · 2.61 KB
/
scrape-blockexplorer.coffee
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
http = require 'http'
assert = require 'assert'
async = require 'async'
{readData} = require './util'
exports.get_unspent_outpoints = (address, callback) ->
http.get {host:"blockexplorer.com", port:80, path:"/address/#{address}"}, (res) ->
readData res, (data) ->
html = data.toString 'utf-8'
[received, sent_transactions] = scrape_address_ledger html, address
async.map sent_transactions, tx_input_outpoints, (err, results) ->
# Set of received outpoints
set = {}
for row in received
set["#{row.hash}:#{row.n}"] = row
# Setminus the spent ones
for outpoints in results
for outpoint in outpoints
delete set[outpoint]
unspent_outpoints = []
for own k, v of set
unspent_outpoints.push v
callback null, unspent_outpoints
tx_input_outpoints = (tx_hash, cb) ->
http.get {host:"blockexplorer.com", port:80, path:"/tx/#{tx_hash}"}, (res) ->
readData res, (data) ->
html = data.toString 'utf-8'
rg = /<td><a name="i[0-9]+" href="\/tx\/([0-9a-fA-F]+)#o([0-9]+)"/g
r = /<td><a name="i[0-9]+" href="\/tx\/([0-9a-fA-F]+)#o([0-9]+)"/
outpoints = []
for text in html.match rg
m = text.match r
outpoints.push "#{m[1]}:#{m[2]}"
cb null, outpoints
satoshis_from_decimal = (text) ->
if text.match /^[0-9]+$/
parseInt(text, 10) * 1e8
else
[left, right] = text.split '.'
assert.ok (right.length <= 8), "right.length > 8"
rightSatoshis = parseInt(right, 10) * Math.pow(10, 8 - right.length)
(left * 1e8) + rightSatoshis
scrape_address_ledger = (html, address) ->
received = []
sent_transactions_set = {}
trs = html.match /<tr>(.|[\r\n])*?<\/tr>/g
assert.ok trs
for tr in trs
amount_match = tr.match /<td>([0-9.]+)<\/td>[ \t\r\n]*<td>(Received|Sent)/
if amount_match
m = tr.match /href="\/tx\/([a-zA-Z0-9]+)#.([0-9]+)"/
assert.ok m, 'hash, n'
hash = m[1]
n = parseInt m[2], 10
m = tr.match /Block ([0-9]+)<\/a>/
assert.ok m, 'block_number'
block_number = parseInt m[1], 10
value_str = amount_match[1]
if tr.match /Received/
received.push {
hash: hash
n: n
satoshis: satoshis_from_decimal(value_str)
amount: value_str
address: address
}
else
sent_transactions_set[hash] = true
sent_transactions = []
for own k of sent_transactions_set
sent_transactions.push k
return [received, sent_transactions]