class VChainClient::BitcoindBlockchainAdapter

Public Class Methods

new(server, port, rpc_username, rpc_password, adapter_config, app_config) click to toggle source
# File lib/vchain_client/bitcoind_blockchain_adapter.rb, line 16
def initialize(server, port, rpc_username, rpc_password, adapter_config, app_config)
  @server = server
  @port = port
  @rpc_username = rpc_username
  @rpc_password = rpc_password

  @config = app_config

  @log = Log4r::Logger["vchain_client"]
end

Public Instance Methods

getName() click to toggle source
# File lib/vchain_client/bitcoind_blockchain_adapter.rb, line 27
def getName()
  return "BitcoindBlockchainAdapter"
end
getOpReturn(raw_tx) click to toggle source
# File lib/vchain_client/bitcoind_blockchain_adapter.rb, line 258
def getOpReturn(raw_tx)
  
  if @log.debug?
    @log.debug("[Bitcoind.getOpReturn] input:")
    @log.debug("-> raw_tx:")
    @log.debug(raw_tx)
  end

  if raw_tx != nil

    tx_unpacked = {}
    tx_unpacked["vout"] = []

    if raw_tx.key?("vout")

      if raw_tx["vout"].length > 0

        raw_tx["vout"].each_with_index { |vout,index|
          vout_t = {}

          vout_t["value"] = 0
          
          if vout.key?("value") 
            vout_t["value"] = vout["value"]
          end

          vout_t["scriptPubKey"] = ""
          if vout.key?("scriptPubKey")
            if vout["scriptPubKey"].key?("hex")
              vout_t["scriptPubKey"] = vout["scriptPubKey"]["hex"]
            end
          end

          tx_unpacked["vout"][index] = vout_t;
        }

        tx_unpacked["vout"].each { |output|
          
          scriptPubKeyArr = output["scriptPubKey"].split()
          scriptPubKeyBinary = scriptPubKeyArr.pack("H*")

          if scriptPubKeyBinary[0] == "\x6a"
            first_ord = scriptPubKeyBinary[1].ord()

            if first_ord <= 75
              return scriptPubKeyBinary[2..first_ord+1]

            elsif first_ord == 0x4c
              return scriptPubKeyBinary[3..scriptPubKeyBinary[2].ord()+1]

            elsif first_ord == 0x4d
              return scriptPubKeyBinary[4..scriptPubKeyBinary[2].ord()+1+256*scriptPubKeyBinary[3].ord()+1]
            end
          end
        }

      end
    end

  else
    if @log.error?
      @log.error("[Bitcoind.getOpReturn] raw_tx is nil")
      @log.error("-> raw_tx:")
      @log.error(raw_tx)
    end
  end

  return nil
end
getRawTx(txid) click to toggle source
# File lib/vchain_client/bitcoind_blockchain_adapter.rb, line 198
def getRawTx(txid)

  if @log.debug?
    @log.debug("[Bitcoind.getRawTx] input:")
    @log.debug("-> txid: #{txid}")
    @log.debug("-> server: #{@server}")
    @log.debug("-> port: #{@port}")
  end

  request = {
    "id"     => Random.rand(0...999999),
    "method" => "getrawtransaction",
    "params" => [txid, 1]
  }

  url = "http://"+ @rpc_username +":"+ @rpc_password +"@"+ @server +":"+ @port +"/"

  begin

    req = RestClient.post(url, request.to_json)

    if req.code != 200
      if @log.error?
        @log.error("[Bitcoind.getRawTx] RestClient.post return code "+ req.code)
        @log.error("-> txid: #{txid}")
        @log.error("-> server: #{@server}")
        @log.error("-> port: #{@port}")
        @log.error("-> request:")
        @log.error(request)
      end

      return nil
    end

    if @log.debug?
      @log.debug("[Bitcoind.getRawTx] response:")
      @log.debug(req.body)
    end

    raw_tx = JSON.parse req.body

    return raw_tx["result"]

  rescue => e
    if @log.error?
      @log.error("[Bitcoind.getRawTx] RestClient.post raised exception:")
      @log.error("#{e.class}, #{e.message}")
      @log.error("-> txid: #{txid}")
      @log.error("-> server: #{@server}")
      @log.error("-> port: #{@port}")
      @log.error("-> request:")
      @log.error(request)
    end

    raise e
  end

  return nil
end
getTx(txid) click to toggle source
# File lib/vchain_client/bitcoind_blockchain_adapter.rb, line 31
def getTx(txid)

  if @@tx_cache.key?(txid)
    if @log.debug?
      @log.debug("[Bitcoind.getTx] '#{txid}' is in a cache")
    end

    return @@tx_cache[txid]
  end

  if @log.debug?
    @log.debug("[Bitcoind.getTx] input:")
    @log.debug("-> txid: #{txid}")
    @log.debug("-> server: #{@server}")
    @log.debug("-> port: #{@port}")
  end

  raw_tx = nil

  begin
    
    raw_tx = self.getRawTx(txid)

  rescue => e
    if @log.error?
      @log.error("[Bitcoind.getTx] getRawTx raised exception:")
      @log.error("#{e.class}, #{e.message}")
      @log.error("-> txid: #{txid}")
      @log.error("-> server: #{@server}")
      @log.error("-> port: #{@port}")
      @log.error("--> txid: #{txid}")
    end

    raise e
  end

  confirmations_threshold = 5
  if @config.key?("blockchain_confirmations")
    confirmations_threshold = @config["blockchain_confirmations"]
  end

  if raw_tx != nil

    if raw_tx.key?("confirmations")

      if raw_tx["confirmations"] > confirmations_threshold

        if raw_tx.key?("blockhash")

          if raw_tx.key?("blocktime")

            op_return = nil

            begin 
              
              op_return = self.getOpReturn(raw_tx)

            rescue => e
              if @log.error?
                @log.error("[Bitcoind.getTx] getOpReturn raised exception:")
                @log.error("#{e.class}, #{e.message}")
                @log.error("-> txid: #{txid}")
                @log.error("--> raw_tx:")
                @log.error(raw_tx)
              end

              raise e
            end

            if op_return != nil
              
              prefix = op_return[0..2]

              if prefix == "VCH"

                op_return = op_return[5..op_return.length]

                out = {
                  "size"            => raw_tx["size"],
                  "block_hash"      => raw_tx["blockhash"],
                  "block_timestamp" => raw_tx["blocktime"],
                  "op_return"       => op_return
                }

                @@tx_cache[txid] = out

                return out
              
              else
                if @log.error?
                  @log.error("[Bitcoind.getTx] wrong prefix '#{prefix}'")
                  @log.error("-> txid: #{txid}")
                  @log.error("-> server: #{@server}")
                  @log.error("-> port: #{@port}")
                  @log.error("-> raw_tx:")
                  @log.error(raw_tx)
                end
              end

            else
              if @log.error?
                @log.error("[Bitcoind.getTx] failed to get OP_RETURN")
                @log.error("-> txid: #{txid}")
                @log.error("-> server: #{@server}")
                @log.error("-> port: #{@port}")
                @log.error("-> raw_tx:")
                @log.error(raw_tx)
              end
            end

          else
            if @log.error?
              @log.error("[Bitcoind.getTx] no 'block_hash' field in response")
              @log.error("-> txid: #{txid}")
              @log.error("-> server: #{@server}")
              @log.error("-> port: #{@port}")
              @log.error("-> raw_tx:")
              @log.error(raw_tx)
            end
          end

        else
          if @log.error?
            @log.error("[Bitcoind.getTx] no 'block_hash' field in response")
            @log.error("-> txid: #{txid}")
            @log.error("-> server: #{@server}")
            @log.error("-> port: #{@port}")
            @log.error("-> raw_tx:")
            @log.error(raw_tx)
          end
        end

      else
        if @log.error?
          @log.error("[Bitcoind.getTx] less than 6 confirmations")
          @log.error("-> txid: #{txid}")
          @log.error("-> server: #{@server}")
          @log.error("-> port: #{@port}")
          @log.error("-> raw_tx:")
          @log.error(raw_tx)
        end
      end

    else
      if @log.error?
        @log.error("[Bitcoind.getTx] no 'confirmations' field")
        @log.error("-> txid: #{txid}")
        @log.error("-> server: #{@server}")
        @log.error("-> port: #{@port}")
        @log.error("-> raw_tx:")
        @log.error(raw_tx)
      end
    end

  else
    if @log.error?
      @log.error("[Bitcoind.getTx] empty raw_tx")
      @log.error("-> txid: #{txid}")
      @log.error("-> server: #{@server}")
      @log.error("-> port: #{@port}")
      @log.error("--> txid: #{txid}")
    end
  end

  return nil
end