summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Taaki <genjix@riseup.net>2014-03-23 23:11:05 (GMT)
committer Amir Taaki <genjix@riseup.net>2014-03-24 19:25:53 (GMT)
commit825b6e87a3a50f53bf7d0b6646d0d61aa080cc74 (patch)
treef6cfb5c72c727fe8c125380cdd946779583cf1d6
parent0b8dd13452c79142b79f106734636b1e064b3c1e (diff)
verifying of history for address against blockchain.info
-rw-r--r--tools/verifier/README14
-rw-r--r--tools/verifier/check_binfo_json.py19
-rw-r--r--tools/verifier/cmp_binfo.py104
-rw-r--r--tools/verifier/cmp_history.py74
-rw-r--r--tools/verifier/fetch-history.cpp83
-rw-r--r--tools/verifier/final_check.py21
-rw-r--r--tools/verifier/query_binfo.py37
7 files changed, 352 insertions, 0 deletions
diff --git a/tools/verifier/README b/tools/verifier/README
new file mode 100644
index 0000000..30bc2c8
--- /dev/null
+++ b/tools/verifier/README
@@ -0,0 +1,14 @@
+# Download the blockchain.info history
+$ python query_binfo.py 1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P history.binfo.json
+$ python check_binfo_json.py history.binfo.json
+OK
+
+# Change constants at top of file first.
+$ g++ -o fetch-history fetch-history.cpp $(pkg-config --cflags --libs libbitcoin)
+
+# Stop anything using your blockchain.
+$ ./fetch-history > history.libbtc.json
+
+$ python cmp_history.py
+$ python final_check.py
+
diff --git a/tools/verifier/check_binfo_json.py b/tools/verifier/check_binfo_json.py
new file mode 100644
index 0000000..43492d8
--- /dev/null
+++ b/tools/verifier/check_binfo_json.py
@@ -0,0 +1,19 @@
+import json
+import sys
+
+def check(history):
+ assert len(history["txs"]) == history["n_tx"]
+ print "OK"
+
+def main(argv):
+ if len(argv) < 2:
+ print >> sys.stderr, "check_binfo_json FILENAME"
+ return -1
+ filename = argv[1]
+ with open(filename) as f:
+ history = json.loads(f.read())
+ check(history)
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
+
diff --git a/tools/verifier/cmp_binfo.py b/tools/verifier/cmp_binfo.py
new file mode 100644
index 0000000..7125c9b
--- /dev/null
+++ b/tools/verifier/cmp_binfo.py
@@ -0,0 +1,104 @@
+import sys
+import json
+import time
+import urllib2
+
+#address = "1Fufjpf9RM2aQsGedhSpbSCGRHrmLMJ7yY"
+address = "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P"
+filename = "history.proc.json"
+limit = 292127;
+
+def read_binfo(address, offset=0, limit=50):
+ url = "https://blockchain.info/rawaddr/%s?offset=%s&limit=%s" % (
+ address, offset, limit)
+ f = urllib2.urlopen(url)
+ return f.read()
+
+def open_all(address, i):
+ with open(filename) as f:
+ history = json.loads(f.read())
+
+ binfo_history = json.loads(read_binfo(address, i * 50, 50))
+ if not binfo_history["txs"]:
+ print "Finished."
+ sys.exit(0)
+
+ return history, binfo_history
+
+def write_all(history):
+ with open(filename, "w") as f:
+ f.write(json.dumps(history, indent=2))
+
+def do_outpart(address, i):
+ history, binfo_history = open_all(address, i)
+
+ for bi_tx in binfo_history["txs"]:
+ if not "block_height" in bi_tx or bi_tx["block_height"] > limit:
+ continue
+ for bi_out in bi_tx["out"]:
+ if bi_out["addr"] != address:
+ continue
+ found = False
+ for row in history["history"]:
+ if (row["output"][0] == bi_tx["hash"] and
+ row["output"][1] == bi_out["n"]):
+ assert row["output_found"] == False
+ row["output_found"] = True
+ found = True
+ if not found:
+ print json.dumps(bi_tx, indent=2)
+ assert found
+
+ write_all(history)
+ print "Done:", i
+
+def do_inpart(address, i):
+ history, binfo_history = open_all(address, i)
+
+ for bi_tx in binfo_history["txs"]:
+ if not "block_height" in bi_tx or bi_tx["block_height"] > limit:
+ continue
+ for bi_idx, bi_inp in enumerate(bi_tx["inputs"]):
+ try:
+ prev = bi_inp["prev_out"]
+ except KeyError:
+ continue
+ if prev["addr"] != address:
+ continue
+ found = False
+ for row in history["history"]:
+ if row["spend"] is None:
+ continue
+ if (row["spend"][0] == bi_tx["hash"] and
+ row["spend"][1] == bi_idx):
+ assert row["spend_found"] == False
+ row["spend_found"] = True
+ found = True
+ if not found:
+ print json.dumps(bi_tx, indent=2)
+ assert found
+
+ write_all(history)
+ print "Done:", i
+
+def check():
+ with open(filename) as f:
+ history = json.loads(f.read())
+ uniq_txs = set()
+ for row in history["history"]:
+ if row["output_found"] == False:
+ print "Not found:", row
+ else:
+ uniq_txs.add(row["output"][0])
+ if row["spend_found"] == False:
+ print "Not found:", row
+ elif row["spend_found"] == True:
+ uniq_txs.add(row["spend"][0])
+ print "Txs:", len(uniq_txs)
+
+#for i in range(999):
+## do_outpart(address, i)
+# do_inpart(address, i)
+# time.sleep(0.5)
+check()
+
diff --git a/tools/verifier/cmp_history.py b/tools/verifier/cmp_history.py
new file mode 100644
index 0000000..9f11cbf
--- /dev/null
+++ b/tools/verifier/cmp_history.py
@@ -0,0 +1,74 @@
+import sys
+import json
+import time
+import urllib2
+
+address = "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P"
+binfo_filename = "history.binfo.json"
+libbtc_filename = "history.libbtc.json"
+limit = 292127;
+output_filename = "history.proc.json"
+
+def json_load(filename):
+ with open(filename) as f:
+ return json.loads(f.read())
+ raise Exception("Problem loading JSON file.")
+
+def mark_output(history, outpoint):
+ found = False
+ for row in history["history"]:
+ if (row["output"][0] == outpoint[0] and
+ row["output"][1] == outpoint[1]):
+ assert row["output_found"] == False
+ row["output_found"] = True
+ found = True
+ if not found:
+ print json.dumps(bi_tx, indent=2)
+ assert found
+
+def mark_input(history, inpoint):
+ found = False
+ for row in history["history"]:
+ if row["spend"] is None:
+ continue
+ if (row["spend"][0] == inpoint[0] and
+ row["spend"][1] == inpoint[1]):
+ assert row["spend_found"] == False
+ row["spend_found"] = True
+ found = True
+ if not found:
+ print json.dumps(bi_tx, indent=2)
+ assert found
+
+def process(tx, history):
+ for output in tx["out"]:
+ if output["addr"] != address:
+ continue
+ outpoint = (tx["hash"], output["n"])
+ mark_output(history, outpoint)
+ for idx, input in enumerate(tx["inputs"]):
+ try:
+ prev = input["prev_out"]
+ except KeyError:
+ continue
+ if prev["addr"] != address:
+ continue
+ inpoint = (tx["hash"], idx)
+ mark_input(history, inpoint)
+
+def main():
+ bi_history = json_load(binfo_filename)
+ lb_history = json_load(libbtc_filename)
+
+ for tx in bi_history["txs"]:
+ if not "block_height" in tx or tx["block_height"] > limit:
+ continue
+ process(tx, lb_history)
+
+ with open(output_filename, "w") as f:
+ f.write(json.dumps(lb_history, indent=2))
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main())
+
diff --git a/tools/verifier/fetch-history.cpp b/tools/verifier/fetch-history.cpp
new file mode 100644
index 0000000..13a8caf
--- /dev/null
+++ b/tools/verifier/fetch-history.cpp
@@ -0,0 +1,83 @@
+#include <bitcoin/bitcoin.hpp>
+using namespace bc;
+
+blockchain* chain = nullptr;
+size_t limit = 292127;
+const std::string address = "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P";
+// Make sure nothing else is using the blockchain.
+const std::string blockchain_path = "/mnt/disk1/blockchain/";
+
+void history_fetched(const std::error_code& ec,
+ const blockchain::history_list& history)
+{
+ if (ec)
+ {
+ log_error() << "Failed to fetch last height: " << ec.message();
+ return;
+ }
+ std::cout << "{\"history\": [" << std::endl;
+ bool first = true;
+ for (const auto& row: history)
+ {
+ if (row.output_height > limit)
+ continue;
+ if (first)
+ first = false;
+ else
+ std::cout << "," << std::endl;
+ std::cout << "{" << std::endl;
+ std::cout << " \"output\": [\"" << row.output.hash << "\", "
+ << row.output.index << "]," << std::endl;
+ std::cout << " \"output_height\": " << row.output_height
+ << "," << std::endl;
+ std::cout << " \"output_found\": false," << std::endl;
+ std::cout << " \"value\": " << row.value << "," << std::endl;
+ std::cout << " \"spend\": ";
+ if (row.spend.hash == null_hash)
+ std::cout << "null";
+ else
+ std::cout << "[\"" << row.spend.hash << "\", "
+ << row.spend.index << "]";
+ std::cout << "," << std::endl;
+ std::cout << " \"spend_height\": ";
+ if (row.spend.hash == null_hash || row.spend_height > limit)
+ {
+ std::cout << "null";
+ std::cout << "," << std::endl;
+ std::cout << " \"spend_found\": null" << std::endl;
+ }
+ else
+ {
+ std::cout << row.spend_height;
+ std::cout << "," << std::endl;
+ std::cout << " \"spend_found\": false" << std::endl;
+ }
+ std::cout << "}";
+ }
+ std::cout << std::endl << "]}" << std::endl;
+}
+
+void blockchain_started(const std::error_code& ec)
+{
+ if (ec)
+ {
+ log_error() << "Blockchain failed to start: " << ec.message();
+ return;
+ }
+ assert(chain);
+ chain->fetch_history(payment_address(address), history_fetched);
+}
+
+int main()
+{
+ threadpool pool(1);
+ leveldb_blockchain ldb_chain(pool);
+ chain = &ldb_chain;
+ ldb_chain.start(blockchain_path, blockchain_started);
+ pool.shutdown();
+ pool.join();
+ ldb_chain.stop();
+ return 0;
+}
+
+
diff --git a/tools/verifier/final_check.py b/tools/verifier/final_check.py
new file mode 100644
index 0000000..dd1efe5
--- /dev/null
+++ b/tools/verifier/final_check.py
@@ -0,0 +1,21 @@
+import json
+
+filename = "history.proc.json"
+
+def check():
+ with open(filename) as f:
+ history = json.loads(f.read())
+ uniq_txs = set()
+ for row in history["history"]:
+ if row["output_found"] == False:
+ print "Not found:", row
+ else:
+ uniq_txs.add(row["output"][0])
+ if row["spend_found"] == False:
+ print "Not found:", row
+ elif row["spend_found"] == True:
+ uniq_txs.add(row["spend"][0])
+ print "Txs:", len(uniq_txs)
+
+check()
+
diff --git a/tools/verifier/query_binfo.py b/tools/verifier/query_binfo.py
new file mode 100644
index 0000000..dc82d08
--- /dev/null
+++ b/tools/verifier/query_binfo.py
@@ -0,0 +1,37 @@
+import json
+import sys
+import time
+import urllib2
+
+def read_binfo(address, offset=0, limit=50):
+ url = "https://blockchain.info/rawaddr/%s?offset=%s&limit=%s" % (
+ address, offset, limit)
+ f = urllib2.urlopen(url)
+ return json.loads(f.read())
+
+def open_all(address):
+ limit = 50
+ history = read_binfo(address, 0, limit)
+ for i in range(1, 9999):
+ history_ext = read_binfo(address, i * limit, limit)
+ if not history_ext["txs"]:
+ return history
+ history["txs"].extend(history_ext["txs"])
+ print "Done:", i
+ time.sleep(0.5)
+ raise Exception("Never reach here.")
+
+def main(argv):
+ if len(argv) < 3:
+ print >> sys.stderr, "query_binfo ADDRESS FILENAME"
+ return -1
+ address = argv[1]
+ output_filename = argv[2]
+ history = open_all(address)
+ with open(output_filename, "w") as f:
+ f.write(json.dumps(history, indent=2))
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
+