Author

Topic: Get block header electrum plugin (Read 1102 times)

jr. member
Activity: 50
Merit: 54
July 05, 2015, 08:52:11 PM
#2
I added information about finding a safe server with Electrum here: https://en.bitcoin.it/wiki/July_2015_Forks

If you find any more servers whose banner lists a safe version, please add it to that list.
sr. member
Activity: 261
Merit: 523
July 05, 2015, 06:16:38 PM
#1
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.

Code:
'''
GET BLOCK HEADER

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

HOW TO
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()
        d.setWindowTitle("Settings")

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

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

    @hook
    def set_enabled(self, enabled):
        BasePlugin.set_enabled(self, enabled)
        print 'set enabled = ' + str(enabled)
        '''
        if enabled:
            self.start_daemon_connection()
        else:
            self.stop_daemon_connection()
        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
         '''

    @hook
    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/main_window.py there is broadcast_transaction()

    @hook
    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)

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

        #see https://electrum.orain.org/wiki/Stratum_protocol_specification

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

        #check its unspent and confirmed
        #addr = '1JfbZRwdDHKZmuiZgYArJZhcuuzuw2HuMu'
        addr = '1EtnpHTBthhXbjLn2TRfJMXu982fjPKcwM'
        print 'getting addr listunspent = ' + addr
        data = self.gui.network.synchronous_get([ ('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')
            return

        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')
                return
            if self.wallet.is_change(addr):
                change_addr = addr
            else:
                cj_addr = addr
                cj_amount = value
        print 'cj=' + cj_addr + ' change=' + change_addr

    @hook
    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
        # trustedcoin.py 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

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

    @hook
    def create_send_tab(self, grid):
        print 'create send tab, put coinjoin fee amount here that updates as the user types in amounts'
        #self.start_daemon_connection()
        #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 https://electrum.orain.org/wiki/Stratum_protocol_specification

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