Skip to content

Instantly share code, notes, and snippets.

@Abstrct
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Abstrct/e77e51f9283b9284b3cf to your computer and use it in GitHub Desktop.
Save Abstrct/e77e51f9283b9284b3cf to your computer and use it in GitHub Desktop.
Copy contents of altcoin defcoind to a postgres database
=begin
WARNING - I think this goes without saying for random gists you find on the internet, but you
probably shouldn't use this in production.
For every altcoin you want to store, create this schema:
CREATE SCHEMA altcoin;
CREATE TABLE altcoin.block (
hash character varying PRIMARY KEY,
details json
);
CREATE TABLE altcoin.transaction (
hash character varying PRIMARY KEY,
block_hash character varying,
details json,
status character varying
);
Todo:
Validate
Missing Blocks
Incomplete Blocks (Missing Transactions)
=end
require 'net/http'
require 'uri'
require 'json'
require 'pg'
$altcoin = 'defcoin'
$rpc_url = 'http://user:password@127.0.0.1:1338'
$db_url = 'host=127.0.0.1 dbname=pgcoin'
# This number should not be higher than the number of connections allowed by postgres
$max_threads = 90
# This class is just a copy from the Bitcoin class shared here: https://en.bitcoin.it/wiki/API_reference_(JSON-RPC)
class CoinRPC
def initialize(service_url)
@uri = URI.parse(service_url)
end
def method_missing(name, *args)
post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
resp['result']
end
def http_post_request(post_body)
http = Net::HTTP.new(@uri.host, @uri.port)
request = Net::HTTP::Post.new(@uri.request_uri)
request.basic_auth @uri.user, @uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
end
class JSONRPCError < RuntimeError; end
end
def insertBlock block
conn = PG.connect($db_url)
conn.prepare('InsertBlock', 'insert into defcoin.block (hash, details) values ($1, $2)')
conn.prepare('InsertGenesisTX', 'insert into defcoin.transaction (hash, block_hash) values ($1, $2)')
conn.prepare('InsertTX', 'insert into defcoin.transaction (hash, block_hash, details) values ($1, $2, $3)')
conn.exec_prepared('InsertBlock', [ block["hash"], JSON.generate(block) ])
block["tx"].each do |tx_hash|
if block["height"] == 0
conn.exec_prepared('InsertGenesisTX', [ tx_hash, block["hash"] ])
else
t = CoinRPC.new($rpc_url)
transaction = t.decoderawtransaction(t.getrawtransaction(tx_hash))
conn.exec_prepared('InsertTX', [ transaction["txid"], block["hash"], JSON.generate(transaction) ])
end
end
conn.finish
Thread.exit
end
def getLastSyncedBlock
conn = PG.connect($db_url)
res = conn.exec('SELECT details->>\'hash\' as h from defcoin.block order by (details->>\'height\')::integer DESC LIMIT 1 ')
unless res.cmd_tuples() == 0
lastBlockHash = res[0]['h']
end
conn.finish
lastBlockHash
end
if $0 == __FILE__
h = CoinRPC.new($rpc_url)
p 'Checking for last stored block'
startingBlock = getLastSyncedBlock()
if startingBlock.nil?
p 'Could not find a block, starting at the Genesis'
block = h.getblock(h.getblockhash(0))
p block["hash"]
Thread.new{insertBlock(block)}
else
p startingBlock
block = h.getblock(startingBlock)
p 'Next Hash Found ' + block["hash"]
end
nextBlockHash = block["nextblockhash"]
while true
if Thread.list.count < $max_threads
begin
while nextBlockHash.nil?
p "Up to date, sleeping"
p block["hash"]
sleep 60
block = h.getblock(block["hash"])
nextBlockHash = block["nextblockhash"]
end
block = h.getblock(nextBlockHash)
nextBlockHash = block["nextblockhash"]
Thread.new{insertBlock(block)}
rescue
p nextBlockHash
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment