def create_fund_and_spend_tx(): spendfrom = spendable_outputs.pop() script = CScript([OP_ADD]) value = spendfrom.vout[0].nValue # Fund transaction txfund = create_transaction(spendfrom, 0, b'', value, script) pad_tx(txfund) txfund.rehash() fundings.append(txfund) # Spend transaction txspend = CTransaction() txspend.vout.append( CTxOut(value-1000, CScript([OP_TRUE]))) txspend.vin.append( CTxIn(COutPoint(txfund.sha256, 0), b'')) # Sign the transaction txspend.vin[0].scriptSig = CScript( b'\x01\x01\x51') # PUSH1(0x01) OP_1 pad_tx(txspend) txspend.rehash() return txspend
def make_spend(sigcheckcount): # Add a funding tx to fundings, and return a tx spending that using # scriptsig. logging.debug("Gen tx with {} sigchecks.".format(sigcheckcount)) def get_script_with_sigcheck(count): return CScript([cds_message, cds_pubkey] + (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] + [OP_CHECKDATASIG]) # get funds locked with OP_1 sourcetx = self.spendable_outputs.popleft() # make funding that forwards to scriptpubkey last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1 fundtx = create_transaction( sourcetx, get_script_with_sigcheck(last_sigcheck_count)) fill_sigcheck_script = get_script_with_sigcheck(30) remaining_sigcheck = sigcheckcount while remaining_sigcheck > 30: fundtx.vout[0].nValue -= 1000 fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script))) remaining_sigcheck -= 30 fundtx.rehash() fundings.append(fundtx) # make the spending scriptsig = CScript([cds_signature]) tx = CTransaction() tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig)) input_index = 2 remaining_sigcheck = sigcheckcount while remaining_sigcheck > 30: tx.vin.append( CTxIn(COutPoint(fundtx.sha256, input_index), scriptsig)) remaining_sigcheck -= 30 input_index += 1 tx.vout.append(CTxOut(0, CScript([OP_RETURN]))) pad_tx(tx) tx.rehash() return tx
def make_spend(scriptpubkey, scriptsig): # Add a funding tx to fundings, and return a tx spending that using # scriptsig. logging.debug( "Gen tx with locking script {} unlocking script {} .".format( scriptpubkey.hex(), scriptsig.hex())) # get funds locked with OP_1 sourcetx = self.spendable_outputs.popleft() # make funding that forwards to scriptpubkey fundtx = create_transaction(sourcetx, scriptpubkey) fundings.append(fundtx) # make the spending tx = CTransaction() tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig)) tx.vout.append(CTxOut(0, CScript([OP_RETURN]))) pad_tx(tx) tx.rehash() return tx
def create_tx_chain(self, unspent, scriptpubkey, chain_len, num_outputs): assert (num_outputs > 0) tx_chain = [unspent] for i in range(chain_len): prev_tx = tx_chain[-1] prev_n = i % num_outputs amount = prev_tx.vout[prev_n].nValue // num_outputs tx = create_transaction(prev_tx, n=prev_n, value=[amount] * num_outputs, sig=CScript([OP_TRUE]), out=scriptpubkey) pad_tx(tx) tx_chain.append(tx) tx_chain.pop(0) # the initial unspent is not part of the chain return tx_chain
def create_transaction(spendfrom, custom_script, amount=None): # Fund and sign a transaction to a given output. # spendfrom should be a CTransaction with first output to OP_TRUE. # custom output will go on position 1, after position 0 which will be # OP_TRUE (so it can be reused). customout = CTxOut(0, bytes(custom_script)) # set output amount to required dust if not given customout.nValue = amount or (len(customout.serialize()) + 148) * 3 ctx = CTransaction() ctx.vin.append(CTxIn(COutPoint(spendfrom.sha256, 0), bytes([OP_TRUE]))) ctx.vout.append(CTxOut(0, bytes([OP_TRUE]))) ctx.vout.append(customout) pad_tx(ctx) fee = len(ctx.serialize()) ctx.vout[0].nValue = spendfrom.vout[0].nValue - customout.nValue - fee ctx.rehash() return ctx
async def test_blockheight_confirmed(self, n, cli, unspent): # Just unique anyone-can-spend scriptpubkey scriptpubkey = CScript([OP_TRUE, OP_DROP, OP_NOP]) scripthash = script_to_scripthash(scriptpubkey) # There should exist any history for scripthash assert_equal(0, len(await cli.call(GET_HISTORY, scripthash))) # Send tx to scripthash and confirm it tx = create_transaction(unspent, n=0, value=unspent.vout[0].nValue, sig=CScript([OP_TRUE]), out=scriptpubkey) pad_tx(tx) self.mine_blocks(n, 1, txns=[tx]) sync_electrum_height(n) # History should now have 1 entry at current tip height res = await cli.call(GET_HISTORY, scripthash) assert_equal(1, len(res)) assert_equal(n.getblockcount(), res[0]['height']) assert_equal(tx.hash, res[0]['tx_hash'])
async def test_blockheight_unconfirmed(self, n, cli, unspent): # Another unique anyone-can-spend scriptpubkey scriptpubkey = CScript([OP_FALSE, OP_DROP, OP_NOP]) scripthash = script_to_scripthash(scriptpubkey) # There should exist any history for scripthash assert_equal(0, len(await cli.call(GET_HISTORY, scripthash))) # Send a chain of three txs. We expect that: # tx1: height 0, signaling unconfirmed with confirmed parents # tx2: height -1, signaling unconfirmed with unconfirmed parents # tx3: height -1, signaling unconfirmed with unconfirmed parents tx1 = create_transaction(unspent, n=0, value=unspent.vout[0].nValue, sig=CScript([OP_TRUE]), out=scriptpubkey) pad_tx(tx1) big_fee = 1 tx2 = create_transaction(tx1, n=0, value=unspent.vout[0].nValue - big_fee, sig=CScript([OP_TRUE]), out=scriptpubkey) pad_tx(tx2) tx3 = create_transaction(tx2, n=0, value=unspent.vout[0].nValue - big_fee, sig=CScript([OP_TRUE]), out=scriptpubkey) pad_tx(tx3) self.p2p.send_txs_and_test([tx1, tx2, tx3], n) wait_for_electrum_mempool(n, count=3) res = await cli.call(GET_HISTORY, scripthash) assert_equal(3, len(res)) def get_tx(txhash): for tx in res: if tx['tx_hash'] == txhash: return tx assert (not "tx not in result") assert_equal(0, get_tx(tx1.hash)['height']) assert_equal(-1, get_tx(tx2.hash)['height']) assert_equal(-1, get_tx(tx3.hash)['height']) # Confirm tx1, see that # tx1: gets tipheight # tx2: gets height 0, tx3 keeps height -1 self.mine_blocks(n, 1, [tx1]) sync_electrum_height(n) res = await cli.call(GET_HISTORY, scripthash) assert_equal(n.getblockcount(), get_tx(tx1.hash)['height']) assert_equal(0, get_tx(tx2.hash)['height']) assert_equal(-1, get_tx(tx3.hash)['height']) # cleanup mempool for next test self.mine_blocks(n, 1, [tx2, tx3]) sync_electrum_height(n) assert (len(n.getrawmempool()) == 0)
def run_test(self): n = self.nodes[0] self.bootstrap_p2p() coinbases = self.mine_blocks(n, 104) # non-coinbase transactions prevtx = coinbases[0] nonstandard_tx = create_transaction(prevtx=prevtx, value=prevtx.vout[0].nValue, n=0, sig=CScript([OP_TRUE]), out=CScript([OP_FALSE, OP_DROP])) prevtx = coinbases[1] p2sh_tx = create_transaction(prevtx=prevtx, value=prevtx.vout[0].nValue, n=0, sig=CScript([OP_TRUE]), out=CScript( [OP_HASH160, DUMMY_HASH, OP_EQUAL])) prevtx = coinbases[2] p2pkh_tx = create_transaction(prevtx=prevtx, value=prevtx.vout[0].nValue, n=0, sig=CScript([OP_TRUE]), out=CScript([ OP_DUP, OP_HASH160, DUMMY_HASH, OP_EQUALVERIFY, OP_CHECKSIG ])) prevtx = coinbases[3] unconfirmed_tx = create_transaction(prevtx=prevtx, value=prevtx.vout[0].nValue, n=0, sig=CScript([OP_TRUE]), out=CScript([ OP_DUP, OP_HASH160, DUMMY_HASH, OP_EQUALVERIFY, OP_CHECKSIG ])) for tx in [nonstandard_tx, p2sh_tx, p2pkh_tx, unconfirmed_tx]: pad_tx(tx) coinbases.extend( self.mine_blocks(n, 1, [nonstandard_tx, p2sh_tx, p2pkh_tx])) self.sync_height() n.sendrawtransaction(ToHex(unconfirmed_tx)) self.wait_for_mempool_count(count=1) async def async_tests(loop): cli = ElectrumConnection(loop) await cli.connect() return await asyncio.gather( self.test_verbose(n, cli, nonstandard_tx.hash, p2sh_tx.hash, p2pkh_tx.hash, unconfirmed_tx.hash), self.test_non_verbose(cli, coinbases, unconfirmed_tx)) loop = asyncio.get_event_loop() loop.run_until_complete(async_tests(loop))