diff --git a/qa/rpc-tests/getblocktemplate.py b/qa/rpc-tests/getblocktemplate_longpoll.py
similarity index 96%
rename from qa/rpc-tests/getblocktemplate.py
rename to qa/rpc-tests/getblocktemplate_longpoll.py
index 500662bf8..263a5f6d5 100755
--- a/qa/rpc-tests/getblocktemplate.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -1,94 +1,92 @@
 #!/usr/bin/env python
 # Copyright (c) 2014 The Bitcoin Core developers
 # Distributed under the MIT software license, see the accompanying
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
-# Exercise the listtransactions API
-
 from test_framework import BitcoinTestFramework
 from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
 from util import *
 
 
 def check_array_result(object_array, to_match, expected):
     """
     Pass in array of JSON objects, a dictionary with key/value pairs
     to match against, and another dictionary with expected key/value
     pairs.
     """
     num_matched = 0
     for item in object_array:
         all_match = True
         for key,value in to_match.items():
             if item[key] != value:
                 all_match = False
         if not all_match:
             continue
         for key,value in expected.items():
             if item[key] != value:
                 raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value)))
             num_matched = num_matched+1
     if num_matched == 0:
         raise AssertionError("No objects matched %s"%(str(to_match)))
 
 import threading
 
 class LongpollThread(threading.Thread):
     def __init__(self, node):
         threading.Thread.__init__(self)
         # query current longpollid
         templat = node.getblocktemplate()
         self.longpollid = templat['longpollid']
         # create a new connection to the node, we can't use the same
         # connection from two threads
         self.node = AuthServiceProxy(node.url, timeout=600)
 
     def run(self):
         self.node.getblocktemplate({'longpollid':self.longpollid})
 
-class GetBlockTemplateTest(BitcoinTestFramework):
+class GetBlockTemplateLPTest(BitcoinTestFramework):
     '''
     Test longpolling with getblocktemplate.
     '''
 
     def run_test(self):
         print "Warning: this test will take about 70 seconds in the best case. Be patient."
         self.nodes[0].setgenerate(True, 10)
         templat = self.nodes[0].getblocktemplate()
         longpollid = templat['longpollid']
         # longpollid should not change between successive invocations if nothing else happens
         templat2 = self.nodes[0].getblocktemplate()
         assert(templat2['longpollid'] == longpollid)
 
         # Test 1: test that the longpolling wait if we do nothing
         thr = LongpollThread(self.nodes[0])
         thr.start()
         # check that thread still lives
         thr.join(5)  # wait 5 seconds or until thread exits
         assert(thr.is_alive())
 
         # Test 2: test that longpoll will terminate if another node generates a block
         self.nodes[1].setgenerate(True, 1)  # generate a block on another node
         # check that thread will exit now that new transaction entered mempool
         thr.join(5)  # wait 5 seconds or until thread exits
         assert(not thr.is_alive())
 
         # Test 3: test that longpoll will terminate if we generate a block ourselves
         thr = LongpollThread(self.nodes[0])
         thr.start()
         self.nodes[0].setgenerate(True, 1)  # generate a block on another node
         thr.join(5)  # wait 5 seconds or until thread exits
         assert(not thr.is_alive())
 
         # Test 4: test that introducing a new transaction into the mempool will terminate the longpoll
         thr = LongpollThread(self.nodes[0])
         thr.start()
         # generate a random transaction and submit it
         (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), Decimal("0.0"), Decimal("0.001"), 20)
         # after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned
         thr.join(60 + 20)
         assert(not thr.is_alive())
 
 if __name__ == '__main__':
-    GetBlockTemplateTest().main()
+    GetBlockTemplateLPTest().main()
 
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
new file mode 100755
index 000000000..0f7859584
--- /dev/null
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+from test_framework import BitcoinTestFramework
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+
+from binascii import a2b_hex, b2a_hex
+from hashlib import sha256
+from struct import pack
+
+
+def check_array_result(object_array, to_match, expected):
+    """
+    Pass in array of JSON objects, a dictionary with key/value pairs
+    to match against, and another dictionary with expected key/value
+    pairs.
+    """
+    num_matched = 0
+    for item in object_array:
+        all_match = True
+        for key,value in to_match.items():
+            if item[key] != value:
+                all_match = False
+        if not all_match:
+            continue
+        for key,value in expected.items():
+            if item[key] != value:
+                raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value)))
+            num_matched = num_matched+1
+    if num_matched == 0:
+        raise AssertionError("No objects matched %s"%(str(to_match)))
+
+def b2x(b):
+    return b2a_hex(b).decode('ascii')
+
+# NOTE: This does not work for signed numbers (set the high bit) or zero (use b'\0')
+def encodeUNum(n):
+    s = bytearray(b'\1')
+    while n > 127:
+        s[0] += 1
+        s.append(n % 256)
+        n //= 256
+    s.append(n)
+    return bytes(s)
+
+def varlenEncode(n):
+    if n < 0xfd:
+        return pack('<B', n)
+    if n <= 0xffff:
+        return b'\xfd' + pack('<H', n)
+    if n <= 0xffffffff:
+        return b'\xfe' + pack('<L', n)
+    return b'\xff' + pack('<Q', n)
+
+def dblsha(b):
+    return sha256(sha256(b).digest()).digest()
+
+def genmrklroot(leaflist):
+    cur = leaflist
+    while len(cur) > 1:
+        n = []
+        if len(cur) & 1:
+            cur.append(cur[-1])
+        for i in range(0, len(cur), 2):
+            n.append(dblsha(cur[i] + cur[i+1]))
+        cur = n
+    return cur[0]
+
+def template_to_bytes(tmpl, txlist):
+    blkver = pack('<L', tmpl['version'])
+    mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
+    timestamp = pack('<L', tmpl['curtime'])
+    nonce = b'\0\0\0\0'
+    blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce
+    blk += varlenEncode(len(txlist))
+    for tx in txlist:
+        blk += tx
+    return blk
+
+def template_to_hex(tmpl, txlist):
+    return b2x(template_to_bytes(tmpl, txlist))
+
+def assert_template(node, tmpl, txlist, expect):
+    rsp = node.getblocktemplate({'data':template_to_hex(tmpl, txlist),'mode':'proposal'})
+    if rsp != expect:
+        raise AssertionError('unexpected: %s' % (rsp,))
+
+class GetBlockTemplateProposalTest(BitcoinTestFramework):
+    '''
+    Test block proposals with getblocktemplate.
+    '''
+
+    def run_test(self):
+        node = self.nodes[0]
+        tmpl = node.getblocktemplate()
+        if 'coinbasetxn' not in tmpl:
+            rawcoinbase = encodeUNum(tmpl['height'])
+            rawcoinbase += b'\x01-'
+            hexcoinbase = b2x(rawcoinbase)
+            hexoutval = b2x(pack('<Q', tmpl['coinbasevalue']))
+            tmpl['coinbasetxn'] = {'data': '01000000' + '01' + '0000000000000000000000000000000000000000000000000000000000000000ffffffff' + ('%02x' % (len(rawcoinbase),)) + hexcoinbase + 'fffffffe' + '01' + hexoutval + '00' + '00000000'}
+        txlist = list(bytearray(a2b_hex(a['data'])) for a in (tmpl['coinbasetxn'],) + tuple(tmpl['transactions']))
+
+        # Test 0: Capability advertised
+        assert('proposal' in tmpl['capabilities'])
+
+        # NOTE: This test currently FAILS (regtest mode doesn't enforce block height in coinbase)
+        ## Test 1: Bad height in coinbase
+        #txlist[0][4+1+36+1+1] += 1
+        #assert_template(node, tmpl, txlist, 'FIXME')
+        #txlist[0][4+1+36+1+1] -= 1
+
+        # Test 2: Bad input hash for gen tx
+        txlist[0][4+1] += 1
+        assert_template(node, tmpl, txlist, 'bad-cb-missing')
+        txlist[0][4+1] -= 1
+
+        # Test 3: Truncated final tx
+        lastbyte = txlist[-1].pop()
+        try:
+            assert_template(node, tmpl, txlist, 'n/a')
+        except JSONRPCException:
+            pass  # Expected
+        txlist[-1].append(lastbyte)
+
+        # Test 4: Add an invalid tx to the end (duplicate of gen tx)
+        txlist.append(txlist[0])
+        assert_template(node, tmpl, txlist, 'bad-txns-duplicate')
+        txlist.pop()
+
+        # Test 5: Add an invalid tx to the end (non-duplicate)
+        txlist.append(bytearray(txlist[0]))
+        txlist[-1][4+1] = b'\xff'
+        assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent')
+        txlist.pop()
+
+        # Test 6: Future tx lock time
+        txlist[0][-4:] = b'\xff\xff\xff\xff'
+        assert_template(node, tmpl, txlist, 'bad-txns-nonfinal')
+        txlist[0][-4:] = b'\0\0\0\0'
+
+        # Test 7: Bad tx count
+        txlist.append(b'')
+        try:
+            assert_template(node, tmpl, txlist, 'n/a')
+        except JSONRPCException:
+            pass  # Expected
+        txlist.pop()
+
+        # Test 8: Bad bits
+        realbits = tmpl['bits']
+        tmpl['bits'] = '1c0000ff'  # impossible in the real world
+        assert_template(node, tmpl, txlist, 'bad-diffbits')
+        tmpl['bits'] = realbits
+
+        # Test 9: Bad merkle root
+        rawtmpl = template_to_bytes(tmpl, txlist)
+        rawtmpl[4+32] = (rawtmpl[4+32] + 1) % 0x100
+        rsp = node.getblocktemplate({'data':b2x(rawtmpl),'mode':'proposal'})
+        if rsp != 'bad-txnmrklroot':
+            raise AssertionError('unexpected: %s' % (rsp,))
+
+        # Test 10: Bad timestamps
+        realtime = tmpl['curtime']
+        tmpl['curtime'] = 0x7fffffff
+        assert_template(node, tmpl, txlist, 'time-too-new')
+        tmpl['curtime'] = 0
+        assert_template(node, tmpl, txlist, 'time-too-old')
+        tmpl['curtime'] = realtime
+
+        # Test 11: Valid block
+        assert_template(node, tmpl, txlist, None)
+
+        # Test 12: Orphan block
+        tmpl['previousblockhash'] = 'ff00' * 16
+        assert_template(node, tmpl, txlist, 'inconclusive-not-best-prevblk')
+
+if __name__ == '__main__':
+    GetBlockTemplateProposalTest().main()