Bitcoin Forum

Bitcoin => Electrum => Topic started by: belcher on July 05, 2015, 11:16:38 PM

Title: Get block header electrum plugin
Post by: belcher on July 05, 2015, 11:16:38 PM
I couldn't find a way to query what the electrum server thinks about the blockchain through the GUI.

During the chain fork after bip66, this information was important. I was able to hack up this plugin.


An electrum plugin for querying the electrum server about it's block headers

1. place plugin in electrum/plugins
2. start electrum on the command line
3. in the gui go Tools -> Plugins
4. enable the GetServerBlockHeaderData and press button
5. input a block height and watch the shell terminal (not electrum's console tab) for the result

example output
[{u'nonce': 697162691, u'prev_block_hash': u'00000000000000000e20bcf213a0bbd6be88d5fede6b060c737f7f8b7f1df504', u'timestamp': 1436136522, u'merkle_root': u'0fa543c7aa9f2b3b6d9755024e586c443cc1cf1cb513f9177ada9c718a1be3e6', u'block_height': 364001, u'version': 3, u'bits': 404111758}]


from PyQt4 import QtCore
from PyQt4.QtGui import *

from electrum.plugins import BasePlugin, hook
from electrum.i18n import _
from electrum.wallet import Abstract_Wallet

from electrum_gui.qt.util import EnterButton

import time, traceback, threading, socket, json

class Plugin(BasePlugin):

    gui = None
    daemon_comm = None

    def fullname(self):
        return 'GetServerBlockHeaderData'

    def description(self):
        return _("Get block header data from the server, useful for obtaining data when the chain forks")

    def requires_settings(self):
        return True

    def settings_widget(self, window):
        return EnterButton(_('GetBlockHeader'), self.settings_dialog)

    def settings_dialog(self):
        print 'pressed settings'
        #self.daemon_comm.send_json({'command': 'echo', 'stuff': 'here'})
        d = QDialog()

        blockheight = QInputDialog.getText(None, 'Block Height', 'Input block height you wish to get the header of')
        if not blockheight[1]:
        blockheight = int(blockheight[0])
        raw =[ ('blockchain.block.get_header', [blockheight]) ])
        print raw
        #blockhash = 10
        #raw =[ ('blockchain.block.get_chunk', [blockhash]) ])
        #jsonraw = str(json.loads(raw))
        #print jsonraw.keys()

        #if d.exec_():
        #    return True
        #    return False

    def set_enabled(self, enabled):
        BasePlugin.set_enabled(self, enabled)
        print 'set enabled = ' + str(enabled)
        if enabled:
        if not enabled and isinstance(self.gui.main_window.wallet, JoinMarketWallet):
            print 'returning wallet to normal'
            self.gui.main_window.wallet = self.gui.main_window.wallet.underlying_wallet

    def load_wallet(self, wallet):
        print 'load wallet'
        #if self.gui and self.gui.main_window.wallet and not isinstance(self.gui.main_window.wallet, JoinMarketWallet):
        #    print 'creating JM wallet'
        #    self.gui.main_window.wallet = JoinMarketWallet(self.gui.main_window.wallet, self.gui.main_window.wallet)

    #in ./gui/qt/ there is broadcast_transaction()

    def init_qt(self, gui):
        print 'init gui'
        self.gui = gui
        #if self.gui.main_window.wallet and not isinstance(self.gui.main_window.wallet, JoinMarketWallet):
        #    print 'creating JM wallet'
        #    self.gui.main_window.wallet = JoinMarketWallet(self.gui.main_window.wallet, self.gui.main_window.wallet)

    def make_unsigned_transaction(self, tx):
        '''called when the user presses send or edits the send dialog'''
        print 'make unsigned tx'
        #print str(tx)


        #get the address and value like this
        tx_hash = '6719c7e225972bb2f935d0f923748a69868fab094fc302bbd64b7d10d89a16b0'
        print 'getting txhash = ' + tx_hash
        raw =[ ('blockchain.transaction.get',[tx_hash]) ])
        print str(raw)

        #check its unspent and confirmed
        #addr = '1JfbZRwdDHKZmuiZgYArJZhcuuzuw2HuMu'
        addr = '1EtnpHTBthhXbjLn2TRfJMXu982fjPKcwM'
        print 'getting addr listunspent = ' + addr
        data =[ ('blockchain.address.listunspent', [addr]) ])
        print str(data)
        #taker needs the following information
        # info on tx being spent, unconfirmed or genuinly just in the utxo set
        #  the value and scriptpubkey (/ address) of such a utxo
        # pushtx, should be easy
        if len(tx.outputs) > 2:
            self.print_error('cant make coinjoins with more than one output address yet')

        cj_addr = None
        change_addr = None
        cj_amount = 0
        for otype, addr, value in tx.outputs:
            if otype != 'address':
                self.print_error('whoops, cant send to places other than addresses')
            if self.wallet.is_change(addr):
                change_addr = addr
                cj_addr = addr
                cj_amount = value
        print 'cj=' + cj_addr + ' change=' + change_addr

    def sign_transaction(self, tx, password):
        '''called when the user types in password after send is clicked'''
        print 'sign tx ' + str(type(tx))
        print str(tx)
        #tx is of instance Transaction
        # need to somehow find out which is the change address
        address = ''
        if len(address) > 0:
            priv = self.wallet.get_private_key(address, password)
            print 'priv = ' + str(priv)
        #the tx needs enough inputs to pay the coinjoin fee, check it has enough
        # if not, repeat the process in make_unsigned_transaction() to get more
        # adds a fee to a tx, look how they do it
        #  they override Wallet class and override get_tx_fee()
        # for us it might be worth overriding the function pointer
        #if/when the user clicks boardcast, then send it to electrum or somehow halt the broadcast
        # and send it to a maker
        # need to add a hook to electrum that has the ability to halt a broadcast
        # ThomasV says he would accept such a hook
        # probably best is that it is able to raise an exception

    def transaction_dialog(self, d):
        '''called when the transaction is displayed to the user right before broadcast'''
        print 'transaction dialog ' + str(type(d))

    def create_send_tab(self, grid):
        print 'create send tab, put coinjoin fee amount here that updates as the user types in amounts'
        #maybe get access to the address/amount field, to be able to tell between output and change
        #better way would be to hook mktx() so you can see outputs

Luckily this page helped

blockchain.block.get_chunk looked like a useful method too but I couldn't figure it out straight away

Title: Re: Get block header electrum plugin
Post by: harding on July 06, 2015, 01:52:11 AM
I added information about finding a safe server with Electrum here:

If you find any more servers whose banner lists a safe version, please add it to that list.